上次讀到src/bitcoind.cpp 中AppInit,大概的流程是
1,解析-?,-h,-help,-version,輸出幫助和版本信息
2,解析-datadir參數(shù),GetDataDir函數(shù)判定所指定數(shù)據(jù)目錄是否合法
3,通過-conf參數(shù),ReadConfigFile函數(shù)讀取配置文件
4,通過-testnet和-regtest參數(shù),ChainNameFromCommandLine函數(shù)設(shè)置的當(dāng)前程序運(yùn)行的網(wǎng)絡(luò)
5,通過-printtoconsole等參數(shù),InitLogging函數(shù)初始化日志記錄以及打印方式
6,InitParameterInteraction函數(shù)初始化網(wǎng)絡(luò)參數(shù)
7,AppInitBasicSetup函數(shù)注冊相應(yīng)的消息以及處理方式
8,AppInitParameterInteraction函數(shù)設(shè)置區(qū)塊鏈運(yùn)行參數(shù)
9,AppInitSanityChecks函數(shù)檢查比特幣運(yùn)行時所需要的所有的庫是否都運(yùn)行正常
10,通過-daemon參數(shù)設(shè)置是否后臺運(yùn)行
11,AppInitMain函數(shù)運(yùn)行主應(yīng)用程序
12,啟動失敗中斷操作和清理工作
AppInit函數(shù)代碼如下:
代碼如下:
54 //////////////////////////////////////////////////////////////////////////////
55 //
56 // Start
57 //
58 bool AppInit(int argc, char* argv[])
59 {
60 bool fRet = false;
61
62 //
63 // Parameters
64 //
65 // If Qt is used, parameters/bitcoin.conf are parsed in qt/bitcoin.cpp's main()
66 gArgs.ParseParameters(argc, argv);
67 //如果命令行參數(shù)是-?,-h,-help,-version的話首先構(gòu)造版本和usage信息
68 // Process help and version before taking care about datadir
69 if (gArgs.IsArgSet("-?") || gArgs.IsArgSet("-h") || gArgs.IsArgSet("-help") || gArgs.IsArgSet("-version"))
70 {
//構(gòu)造版本字符串,例如:Bitcoin Core Daemon version v0.16.0rc2
71 std::string strUsage = strprintf(_("%s Daemon"), _(PACKAGE_NAME)) + " " + _("version") + " " + FormatFullVersion() + "\n";
72
//如果是-version,構(gòu)造追加license信息
73 if (gArgs.IsArgSet("-version"))
74 {
75 strUsage += FormatParagraph(LicenseInfo());
76 }
//如果是-?,-h,-help,構(gòu)造追加usage信息
77 else
78 {
79 strUsage += "\n" + _("Usage:") + "\n" +
80 " bitcoind [options] " + strprintf(_("Start %s Daemon"), _(PACKAGE_NAME)) + "\n";
81
82 strUsage += "\n" + HelpMessage(HMM_BITCOIND);
83 }
84
85 fprintf(stdout, "%s", strUsage.c_str());
86 return true;
87 }
88
//檢測數(shù)據(jù)目錄
89 try
90 {
//解析-datadir參數(shù),通過GetDataDir檢測和處理-datadir參數(shù)指定的目錄
91 if (!fs::is_directory(GetDataDir(false)))
92 {
93 fprintf(stderr, "Error: Specified data directory \"%s\" does not exist.\n", gArgs.GetArg("-datadir", "").c_str());
94 return false;
95 }
//通過-conf讀取配置文件
96 try
97 {
98 gArgs.ReadConfigFile(gArgs.GetArg("-conf", BITCOIN_CONF_FILENAME));
99 } catch (const std::exception& e) {
100 fprintf(stderr,"Error reading configuration file: %s\n", e.what());
101 return false;
102 }
//檢測-testnet和-regtest設(shè)置的當(dāng)前程序運(yùn)行的網(wǎng)絡(luò)
103 // Check for -testnet or -regtest parameter (Params() calls are only valid after this clause)
104 try {
105 SelectParams(ChainNameFromCommandLine());
106 } catch (const std::exception& e) {
107 fprintf(stderr, "Error: %s\n", e.what());
108 return false;
109 }
110
//不合法的參數(shù)字符檢測
111 // Error out when loose non-argument tokens are encountered on command line
112 for (int i = 1; i < argc; i++) {
113 if (!IsSwitchChar(argv[i][0])) {
114 fprintf(stderr, "Error: Command line contains unexpected token '%s', see bitcoind -h for a list of options.\n", argv[i]);
115 return false;
116 }
117 }
118
//設(shè)置-server參數(shù)為true,而-server參數(shù)表示是否接收RPC命令,
//這里因為是bitcoind,默認(rèn)作為核心服務(wù)器接收bitcoin-cli以及bitcoin-tx傳送的命令
119 // -server defaults to true for bitcoind but not for the GUI so do this here
120 gArgs.SoftSetBoolArg("-server", true);
121 // Set this early so that parameter interactions go to console
//初始化日志記錄以及打印方式
122 InitLogging();
//初始化網(wǎng)絡(luò)參數(shù)
123 InitParameterInteraction();
//注冊相應(yīng)的消息以及處理方式
124 if (!AppInitBasicSetup())
125 {
126 // InitError will have been called with detailed error, which ends up on console
127 return false;
128 }
//設(shè)置區(qū)塊鏈運(yùn)行參數(shù)
129 if (!AppInitParameterInteraction())
130 {
131 // InitError will have been called with detailed error, which ends up on console
132 return false;
133 }
//Sanity Check是用來檢查比特幣運(yùn)行時所需要的所有的庫是否都運(yùn)行正常
134 if (!AppInitSanityChecks())
135 {
136 // InitError will have been called with detailed error, which ends up on console
137 return false;
138 }
//通過-daemon參數(shù)設(shè)置是否后臺運(yùn)行
139 if (gArgs.GetBoolArg("-daemon", false))
140 {
141 #if HAVE_DECL_DAEMON
142 fprintf(stdout, "Bitcoin server starting\n");
143
144 // Daemonize
145 if (daemon(1, 0)) { // don't chdir (1), do close FDs (0)
146 fprintf(stderr, "Error: daemon() failed: %s\n", strerror(errno));
147 return false;
148 }
149 #else
150 fprintf(stderr, "Error: -daemon is not supported on this operating system\n");
151 return false;
152 #endif // HAVE_DECL_DAEMON
153 }
//后臺運(yùn)行后鎖定數(shù)據(jù)目錄
154 // Lock data directory after daemonization
155 if (!AppInitLockDataDirectory())
156 {
157 // If locking the data directory failed, exit immediately
158 return false;
159 }
//運(yùn)行主應(yīng)用程序
160 fRet = AppInitMain();
161 }
162 catch (const std::exception& e) {
163 PrintExceptionContinue(&e, "AppInit()");
164 } catch (...) {
165 PrintExceptionContinue(nullptr, "AppInit()");
166 }
167
//如果返回值fRet為false,那么強(qiáng)制結(jié)束所有線程;否則就等待所有線程運(yùn)行結(jié)束
168 if (!fRet)
169 {
170 Interrupt();
171 } else {
172 WaitForShutdown();
173 }
//最后通過ShutDown()完成清理工作
174 Shutdown();
175
176 return fRet;
177 }
178
大概瀏覽了以下AppInit函數(shù)的實現(xiàn),發(fā)現(xiàn)大部分都是在解析bitcoind的命令行參數(shù),首先解析-?,-h,-help幫助信息和-version版本信息,91行執(zhí)行GetDataDir函數(shù),檢查數(shù)據(jù)目錄是否合法,通過-datadir參數(shù)進(jìn)行設(shè)置,該目錄下主要保存同步的區(qū)塊信息,錢包信息,配置信息等等幾乎所有的區(qū)塊鏈運(yùn)行信息都保存在這里,這個函數(shù)在src/util.cpp中實現(xiàn),代碼如下:
581 static fs::path pathCached;
582 static fs::path pathCachedNetSpecific;
583 static CCriticalSection csPathCached;
584
585 const fs::path &GetDataDir(bool fNetSpecific)
586 {
587
588 LOCK(csPathCached);
589
//判斷fNetSpecific是否為true,true使用pathCachedNetSpecific(網(wǎng)絡(luò)路徑),否則使用
//pathCached(本地路徑)
590 fs::path &path = fNetSpecific ? pathCachedNetSpecific : pathCached;
591
//如果path不為空,返回path
592 // This can be called during exceptions by LogPrintf(), so we cache the
593 // value so we don't have to do memory allocations after that.
594 if (!path.empty())
595 return path;
596
//如果有通過-datadir參數(shù)指定目錄
597 if (gArgs.IsArgSet("-datadir")) {
598 path = fs::system_complete(gArgs.GetArg("-datadir", ""));
//檢測參數(shù)傳入的路徑是否為目錄,不為目錄的話,置空path返回
599 if (!fs::is_directory(path)) {
600 path = "";
601 return path;
602 }
//如果沒有通過-datadir參數(shù)指定目錄,使用GetDefaultDataDir獲取默認(rèn)目錄
603 } else {
604 path = GetDefaultDataDir();
605 }
//如果事網(wǎng)絡(luò)路徑,修改path為BaseParams().DataDir();
606 if (fNetSpecific)
607 path /= BaseParams().DataDir();
608
//創(chuàng)建wallets目錄
609 if (fs::create_directories(path)) {
610 // This is the first run, create wallets subdirectory too
611 fs::create_directories(path / "wallets");
612 }
613
614 return path;
615 }
AppInit函數(shù)105行: SelectParams(ChainNameFromCommandLine());設(shè)置的當(dāng)前程序運(yùn)行的網(wǎng)絡(luò),有三種:Main,Testnet,Regtest
ChainNameFromCommandLine函數(shù),在src/chainparamsbase.cpp中實現(xiàn),代碼如下
90 std::string ChainNameFromCommandLine()
91 {
//獲取命令行-regtest參數(shù),是否為私有網(wǎng)
92 bool fRegTest = gArgs.GetBoolArg("-regtest", false);
//獲取命令行-testnet參數(shù),是否為測試網(wǎng)
93 bool fTestNet = gArgs.GetBoolArg("-testnet", false);
94 //不能同時配置兩個參數(shù)
95 if (fTestNet && fRegTest)
96 throw std::runtime_error("Invalid combination of -regtest and -testnet.");
//如果為私網(wǎng),返回私網(wǎng)
97 if (fRegTest)
98 return CBaseChainParams::REGTEST;
//如果為測試網(wǎng),返回測試網(wǎng)
99 if (fTestNet)
100 return CBaseChainParams::TESTNET;
//不是以上兩種的返回主網(wǎng)
101 return CBaseChainParams::MAIN;
102 }
ChainNameFromCommandLine
AppInit函數(shù)122行:InitLogging函數(shù),初始化日志記錄以及打印方式,在src/init.cpp中實現(xiàn),代碼如下
void InitLogging()
{
//通過-printtoconsole參數(shù)設(shè)置是否打印日志到終端
fPrintToConsole = gArgs.GetBoolArg("-printtoconsole", false);
//通過-logtimestamps參數(shù)設(shè)置每一條輸出信息附帶時間戳,默認(rèn)值為附帶
fLogTimestamps = gArgs.GetBoolArg("-logtimestamps", DEFAULT_LOGTIMESTAMPS);
//通過-logtimemicros設(shè)置時間戳精確到微秒精度,默認(rèn)不附加
fLogTimeMicros = gArgs.GetBoolArg("-logtimemicros", DEFAULT_LOGTIMEMICROS);
//通過-logips設(shè)置輸出信息中附加ip地址,默認(rèn)不附加
fLogIPs = gArgs.GetBoolArg("-logips", DEFAULT_LOGIPS);
LogPrintf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
std::string version_string = FormatFullVersion();
#ifdef DEBUG
version_string += " (debug build)";
#else
version_string += " (release build)";
#endif
LogPrintf(PACKAGE_NAME " version %s\n", version_string);
}
AppInit函數(shù)123行: InitParameterInteraction();初始化網(wǎng)絡(luò)參數(shù)函數(shù)后的其他函數(shù),下篇繼續(xù)