接下来我们来看下一些程序初始化设置的一些操作,主要涉及的文件:
bitcoind.cpp、init.cpp、util.cpp
首先是InitLogging(), 设置日志相关的参数, 默认日志存储在$DataDir/debug.log
void InitLogging()
{
//是否打印日志到console终端
fPrintToConsole = gArgs.GetBoolArg("-printtoconsole", false);
//是否记录时间戳到日志中
fLogTimestamps = gArgs.GetBoolArg("-logtimestamps", DEFAULT_LOGTIMESTAMPS);
//是否记录微秒至日志中
fLogTimeMicros = gArgs.GetBoolArg("-logtimemicros", DEFAULT_LOGTIMEMICROS);
//是否记录IP至日志中
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");
//打印版本详细信息
LogPrintf("Bitcoin version %s\n", FormatFullVersion());
}
InitParameterInteraction()是处理网络连接相关的参数设置,具体可参考:http://www.jianshu.com/p/811c0c01eedb
AppInitBasicSetup()程序初始化的一些与系统相关的基本设置, 请参考:http://www.jianshu.com/p/d42558e7e8e8
接下来主要分析一下函数AppInitParameterInteraction()的内容。
// if using block pruning, then disallow txindex
if (gArgs.GetArg("-prune", 0)) {
if (gArgs.GetBoolArg("-txindex", DEFAULT_TXINDEX))
return InitError(_("Prune mode is incompatible with -txindex."));
}
-prune与-txindex是互斥的两个参数,即最多只能设置其中一个参数。因为prune参数是为了节省区块存储空间而对区块进行修剪,不保留无用数据。而txindex是需要维护整个区块链网络中所有交易的全索引。
接着将根据提供的启动参数-debug以及-debugexclude设置log记录的类别。
if (gArgs.IsArgSet("-debug")) {
// Special-case: if -debug=0/-nodebug is set, turn off debugging messages
const std::vector<std::string> categories = gArgs.GetArgs("-debug");
if (find(categories.begin(), categories.end(), std::string("0")) == categories.end()) {//如果没有设置-debug=0或-nodebug,则遍历提供的-debug参数值
for (const auto& cat : categories) {
uint32_t flag = 0;
if (!GetLogCategory(&flag, &cat)) {//查询日志类别是否存在
InitWarning(strprintf(_("Unsupported logging category %s=%s."), "-debug", cat));
continue;
}
logCategories |= flag;//记录哪个日志种类的日志需要被记录,每个日志种类标识占1bit
}
}
}
方法GetLogCategory()将根据提供的debug参数值str在数组LogCategories中搜索,如果存在返回true(同时将该日志类别对应的编号f返回),否则返回false。我们来看下GetLogCategory是如何查找相关的日志类别的:
bool GetLogCategory(uint32_t *f, const std::string *str)
{
if (f && str) {
if (*str == "") {
*f = BCLog::ALL;
return true;
}
for (unsigned int i = 0; i < ARRAYLEN(LogCategories); i++) {
if (LogCategories[i].category == *str) {
*f = LogCategories[i].flag;
return true;
}
}
}
return false;
}
我们来看一下LogCategories的定义,它是一个CLogCategoryDesc数组,CLogCategoryDesc类型的由两个参数,第一个为以2的指数计算的标志位,这么设计的原因是方便通过移位运算记录哪些类别的日志需要记录;第二个为日志种类。
const CLogCategoryDesc LogCategories[] =
{
{BCLog::NONE, "0"},
{BCLog::NET, "net"},
{BCLog::TOR, "tor"},
{BCLog::MEMPOOL, "mempool"},
{BCLog::HTTP, "http"},
{BCLog::BENCH, "bench"},
{BCLog::ZMQ, "zmq"},
{BCLog::DB, "db"},
{BCLog::RPC, "rpc"},
{BCLog::ESTIMATEFEE, "estimatefee"},
{BCLog::ADDRMAN, "addrman"},
{BCLog::SELECTCOINS, "selectcoins"},
{BCLog::REINDEX, "reindex"},
{BCLog::CMPCTBLOCK, "cmpctblock"},
{BCLog::RAND, "rand"},
{BCLog::PRUNE, "prune"},
{BCLog::PROXY, "proxy"},
{BCLog::MEMPOOLREJ, "mempoolrej"},
{BCLog::LIBEVENT, "libevent"},
{BCLog::COINDB, "coindb"},
{BCLog::QT, "qt"},
{BCLog::LEVELDB, "leveldb"},
{BCLog::ALL, "1"},
{BCLog::ALL, "all"},
};
namespace BCLog {
enum LogFlags : uint32_t {
NONE = 0,
NET = (1 << 0),
TOR = (1 << 1),
MEMPOOL = (1 << 2),
HTTP = (1 << 3),
BENCH = (1 << 4),
ZMQ = (1 << 5),
DB = (1 << 6),
RPC = (1 << 7),
ESTIMATEFEE = (1 << 8),
ADDRMAN = (1 << 9),
SELECTCOINS = (1 << 10),
REINDEX = (1 << 11),
CMPCTBLOCK = (1 << 12),
RAND = (1 << 13),
PRUNE = (1 << 14),
PROXY = (1 << 15),
MEMPOOLREJ = (1 << 16),
LIBEVENT = (1 << 17),
COINDB = (1 << 18),
QT = (1 << 19),
LEVELDB = (1 << 20),
ALL = ~(uint32_t)0,
};
}
接下来参数-debugexclude正好与-debug参数相反,用于设置不需要记录哪些类别的日志,可以看到在计算logCategories用的操作符是先对标志位求“反“再求“与”,目的就是把logCategories对应的标志位置为0.
// Now remove the logging categories which were explicitly excluded
for (const std::string& cat : gArgs.GetArgs("-debugexclude")) {
uint32_t flag = 0;
if (!GetLogCategory(&flag, &cat)) {
InitWarning(strprintf(_("Unsupported logging category %s=%s."), "-debugexclude", cat));
continue;
}
logCategories &= ~flag;
}
接下来是检查一些过时的参数设置,并予以提示。
// Check for -debugnet
if (gArgs.GetBoolArg("-debugnet", false))
InitWarning(_("Unsupported argument -debugnet ignored, use -debug=net."));
// Check for -socks - as this is a privacy risk to continue, exit here
if (gArgs.IsArgSet("-socks"))
return InitError(_("Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported."));
// Check for -tor - as this is a privacy risk to continue, exit here
if (gArgs.GetBoolArg("-tor", false))
return InitError(_("Unsupported argument -tor found, use -onion."));
if (gArgs.GetBoolArg("-benchmark", false))
InitWarning(_("Unsupported argument -benchmark ignored, use -debug=bench."));
if (gArgs.GetBoolArg("-whitelistalwaysrelay", false))
InitWarning(_("Unsupported argument -whitelistalwaysrelay ignored, use -whitelistrelay and/or -whitelistforcerelay."));
if (gArgs.IsArgSet("-blockminsize"))
InitWarning("Unsupported argument -blockminsize ignored.");
接下来是交易池检查(-checkmempool)、块index(-checkblockindex)以及检查点(-checkpoints)参数的相关设置。-checkmempool参数指定交易池检查的频率,-checkblockindex表示是否需要对块的索引进行检测,-checkpoints是为了防止节点接受最后一个检查点前的fork链,在一定程度上保证了区块链的安全性。
int ratio = std::min<int>(std::max<int>(gArgs.GetArg("-checkmempool", chainparams.DefaultConsistencyChecks() ? 1 : 0), 0), 1000000);
if (ratio != 0) {
mempool.setSanityCheck(1.0 / ratio);
}
fCheckBlockIndex = gArgs.GetBoolArg("-checkblockindex", chainparams.DefaultConsistencyChecks());
fCheckpointsEnabled = gArgs.GetBoolArg("-checkpoints", DEFAULT_CHECKPOINTS_ENABLED);
下面的两个参数是与交易池容量相关的,其中-maxmempool用于设置交易池容量的最大值(注意单位是兆M),另外一个参数是- limitdescendantsize,从其英文注释Do not accept transactions if any ancestor would have more than <n> kilobytes of in-mempool descendants,可以看出如果某个交易的任何一个父交易的所有子交易在mempool中的大小总和大于了该参数的值(注意单位,不懂为何默认值DEFAULT_DESCENDANT_SIZE_LIMIT设置为101,后面又乘以1000*40??),则不接受该交易,具体原因我们等分析到该参数的具体实际使用时再来分析。
// mempool limits
int64_t nMempoolSizeMax = gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000;
int64_t nMempoolSizeMin = gArgs.GetArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT) * 1000 * 40;
if (nMempoolSizeMax < 0 || nMempoolSizeMax < nMempoolSizeMin)
return InitError(strprintf(_("-maxmempool must be at least %d MB"), std::ceil(nMempoolSizeMin / 1000000.0)));
好了,本篇就先分析到这。很多内容菜菜子(http://www.jianshu.com/u/30081a05cf95)分析的很详细,对我的理解帮助也很大。有些内容目前仅仅是按照自己的理解写出来的,难免与实际的作用会有一些出路,我们随着源码分析的不断深入,必将回过头了验证与纠正我们前面的分析。
因本人水平有限,如有问题,欢迎大家批评指出,非常感谢。