本文是以一个整体的角度分析程序初始化过程中所做的操作,整个初始化过程如果要分开来细讲可以写好几篇,后面可能会根据实际情况具体展开分析。
主程序的入口函数main()在bitcoind.cpp文件中:
int main(int argc, char* argv[])
{
SetupEnvironment();
// Connect bitcoind signal handlers
noui_connect();
return (AppInit(argc, argv) ? EXIT_SUCCESS : EXIT_FAILURE);
}
一步一步分析下。
一、SetupEnvironment() ,设置运行环境
二、noui_connect(),连接bitcoind信号处理器
三、AppInit(argc, argv), 应用初始化,这里有大量的初始化操作,接下来一步一步分析下这个函数的源码:
1.解析运行输入的参数,保存在 mapArgs 这个map容器中
// If Qt is used, parameters/bitcoin.conf are parsed in qt/bitcoin.cpp's main()
gArgs.ParseParameters(argc, argv);
2.处理查询帮助信息和版本信息的命令
// Process help and version before taking care about datadir
if (gArgs.IsArgSet("-?") || gArgs.IsArgSet("-h") || gArgs.IsArgSet("-help") || gArgs.IsArgSet("-version"))
{
std::string strUsage = strprintf(_("%s Daemon"), _(PACKAGE_NAME)) + " " + _("version") + " " + FormatFullVersion() + "\n";
if (gArgs.IsArgSet("-version"))
{
strUsage += FormatParagraph(LicenseInfo());
}
else
{
strUsage += "\n" + _("Usage:") + "\n" +
" bitcoind [options] " + strprintf(_("Start %s Daemon"), _(PACKAGE_NAME)) + "\n";
strUsage += "\n" + HelpMessage(HMM_BITCOIND);
}
fprintf(stdout, "%s", strUsage.c_str());
return true;
}
3.检查应用的数据目录
if (!fs::is_directory(GetDataDir(false)))
{
fprintf(stderr, "Error: Specified data directory \"%s\" does not exist.\n", gArgs.GetArg("-datadir", "").c_str());
return false;
}
4.读取配置文件
try
{
gArgs.ReadConfigFile(gArgs.GetArg("-conf", BITCOIN_CONF_FILENAME));
} catch (const std::exception& e) {
fprintf(stderr,"Error reading configuration file: %s\n", e.what());
return false;
}
5.检查判断是主网还是测试网络,并设置区块链的全局参数
// Check for -testnet or -regtest parameter (Params() calls are only valid after this clause)
try {
SelectParams(ChainNameFromCommandLine());
} catch (const std::exception& e) {
fprintf(stderr, "Error: %s\n", e.what());
return false;
}
6.设置server标识为true,即启用RPC服务
// -server defaults to true for bitcoind but not for the GUI so do this here
gArgs.SoftSetBoolArg("-server", true);
7.初始化日志
// Set this early so that parameter interactions go to console
InitLogging();
8.初始化参数交互,即根据规则将一些设置的参数转化为设置其他参数
InitParameterInteraction();
8.建立Bitcoin Core的基础上下文环境
if (!AppInitBasicSetup())
{
// InitError will have been called with detailed error, which ends up on console
return false;
}
9.初始化参数交互,根据设置的参数做一些逻辑条件判断,根据情况显示相应的警告信息或者异常信息,也会有相关计算,将结果存储在内部变量中
if (!AppInitParameterInteraction())
{
// InitError will have been called with detailed error, which ends up on console
return false;
}
10.完整性检查
if (!AppInitSanityChecks())
{
// InitError will have been called with detailed error, which ends up on console
return false;
}
11.判断是否需要在后台运行(Daemonize)
if (gArgs.GetBoolArg("-daemon", false))
{
#if HAVE_DECL_DAEMON
fprintf(stdout, "Bitcoin server starting\n");
// Daemonize
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
}
12.锁住Bitcoin Core数据目录
// Lock data directory after daemonization
if (!AppInitLockDataDirectory())
{
// If locking the data directory failed, exit immediately
return false;
}
13.Bitcoin Core的主要初始化工作
fRet = AppInitMain();
14.监结束程序的请求,若有结束程序的请求,则完成结束程序的相关操作
if (!fRet)
{
Interrupt();
} else {
WaitForShutdown();
}
Shutdown();