比特币源码分析(10) - 可执行程序 - Bitcoind
2017-09-08 15:48
471 查看
0x01 AppInit
接下来分析main函数中的最后一个函数AppInit,首先看前面一部分代码,
// src/bitcoind.cpp line 65-95 boost::thread_group threadGroup; CScheduler scheduler; bool fRet = false; // Parameters // // If Qt is used, parameters/bitcoin.conf are parsed in qt/bitcoin.cpp's main() gArgs.ParseParameters(argc, argv); // 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; }
程序首先定义了一个线程组
threadGroup,线程组的功能就是分组管理线程,功能和http://blog.csdn.net/pure_lady/article/details/77675915#t3 中介绍的
Thread功能几乎一样。接下来定义了一个
scheduler,这个类的声明在
src/scheduler.h中,根据代码中的介绍,
// // Simple class for background tasks that should be run // periodically or once "after a while" // // Usage: // // CScheduler* s = new CScheduler(); // s->scheduleFromNow(doSomething, 11); // Assuming a: void doSomething() { } // s->scheduleFromNow(std::bind(Class::func, this, argument), 3); // boost::thread* t = new boost::thread(boost::bind(CScheduler::serviceQueue, s)); // // ... then at program shutdown, clean up the thread running serviceQueue: // t->interrupt(); // t->join(); // delete t; // delete s; // Must be done after thread is interrupted/joined. //
主要是用来管理后台任务,主要的两个函数是
scheduleFromNow和
scheduleEvery,分别表示从现在开始是过一段时间执行某函数一次,和从现在开始每隔几秒执行某函数一次。也可创建一个新的线程去执行任务,而不影响主线程的执行。
定义完这两个变量之后,下面一行是
gArgs.ParseParameters(argc, argv);,作用是解析bitcoind命令行传入的参数,其中
gArgs的定义在
src/util.h中,类型是
ArgsManager,
ParseParameters()是该类中的一个主要成员函数,功能是将传入的参数进行解析并存入到两个
map当中。
解析完参数之后,下面就开始进行一系列参数设置,这部分分析的最后一部分代码,也就是上面的那个
if语句,功能是判断参数中是否有显示
help或者
version信息,如果有,就直接显示对应的信息,然后退出程序,忽略其他所有的参数。
再来看接下来的一段代码,
// src/bitcoind.cpp line 99-118 if (!fs::is_directory(GetDataDir(false))) // 检查数据目录 { fprintf(stderr, "Error: Specified data directory \"%s\" does not exist.\n", gArgs.GetArg("-datadir", "").c_str()); return false; } 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; } // 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; }
这段代码首先检查数据目录是否合法,数据目录在Ubuntu下默认的路径是
~/.bitcoin/,当然也能通过
-datadir参数进行设置,该目录下主要保存同步的区块信息,钱包信息,配置信息等等几乎所有的区块链运行信息都保存在这里。然后开始读取配置文件,配置文件的默认名称是
~/.bitcoin/bitcoinf.conf也是在数据目录下,不过默认是没有这个文件的,进入
ReadConfigFile可以看到文件不存在也是可以的。
// src/util.cpp line 599-623 void ArgsManager::ReadConfigFile(const std::string& confPath) { fs::ifstream streamConfig(GetConfigFile(confPath)); if (!streamConfig.good()) return; // No bitcoin.conf file is OK { LOCK(cs_args); std::set<std::string> setOptions; setOptions.insert("*"); for (boost::program_options::detail::config_file_iterator it(streamConfig, setOptions), end; it != end; ++it) { // Don't overwrite existing settings so command line settings override bitcoin.conf std::string strKey = std::string("-") + it->string_key; std::string strValue = it->value[0]; InterpretNegativeSetting(strKey, strValue); if (mapArgs.count(strKey) == 0) mapArgs[strKey] = strValue; mapMultiArgs[strKey].push_back(strValue); } } // If datadir is changed in .conf file: ClearDatadirCache(); }
接下来是这句
SelectParams(ChainNameFromCommandLine());,首先通过
ChainNameFromCommandLine()获取命令行中设置的当前程序运行的网络,包括以下三种:
Main:表示主网,也就是当前比特币所有用户交易的网络,bitcoind中的默认值。
Testnet:测试网,测试网中专门有一条测试链,所有的交易都只是用于测试,并且测试网中的币可以方便的获取,主要目的就是模拟真实交易环境测试新的功能。
Regtest:回归测试,又称为私有网,用于个人开发测试,挖矿难度较低,并且参数都可以自行设置。
所以一般在本地环境开始时使用Regtest,本地开发完成后,进入Testnet进行大规模实际环境测试,运行正常后再进入主网,这也是目前众多区块链(ICO)项目的主流开发路线。
回到代码中,获取到当前的网络之后通过
SelectParams()根据不同的网络创建不同的共识参数,实现的方式是使用三个继承类
CMainParams,
CTestNetParams,
CRegTestParams继承基类
CChainParams,然后根据选择的不同的网络返回不同的继承类,返回值由一个
CChainParams类型的智能指针(unique_ptr)
globalChainParams来接收,最后使用时就用这个智能指针来访问相应的共识参数。所谓智能指针就是当指针离开作用域时自动的删除(使用delete)所指向的对象。
设置好网络后,下面一部分代码是用来判断命令行中是否存在错误的参数,判断方法是看每一个参数的第一个字母是否为
-或者在windows环境中
- or /,如果不是就报错然后退出程序。
// src/bitcoind.cpp line 119-125 // Error out when loose non-argument tokens are encountered on command line for (int i = 1; i < argc; i++) { if (!IsSwitchChar(argv[i][0])) { fprintf(stderr, "Error: Command line contains unexpected token '%s', see bitcoind -h for a list of options.\n", argv[i]); exit(EXIT_FAILURE); } }
相关文章推荐
- 比特币源码分析(10) - 可执行程序 - Bitcoind
- 比特币源码解析(13) - 可执行程序 - Bitcoind
- 比特币源码解析(14) - 可执行程序 - Bitcoind
- 比特币源码解析(15) - 可执行程序 - Bitcoind
- 比特币源码解析(20) - 可执行程序 - Bitcoind
- 比特币源码解析(17) - 可执行程序 - Bitcoind
- 比特币源码解析(9) - 可执行程序 - Bitcoind
- 比特币源码解析(21) - 可执行程序 - Bitcoind
- 比特币源码解析(22) - 可执行程序 - Bitcoind
- 比特币源码解析(9) - 可执行程序 - Bitcoind
- 比特币源码解析(12) - 可执行程序 - Bitcoind
- 比特币源码解析(16) - 可执行程序 - Bitcoind
- 比特币源码解析(16) - 可执行程序 - Bitcoind
- 比特币源码解析(17) - 可执行程序 - Bitcoind
- 比特币源码解析(19) - 可执行程序 - Bitcoind
- 比特币源码解析(18) - 可执行程序 - Bitcoind
- 比特币源码解析(20) - 可执行程序 - Bitcoind
- 比特币源码解析(14) - 可执行程序 - Bitcoind
- 比特币源码解析(21) - 可执行程序 - Bitcoind
- 比特币源码解析(22) - 可执行程序 - Bitcoind