主页 > 苹果手机imtoken怎么下载 > 比特币源码研究10——程序入口函数解析(九)
比特币源码研究10——程序入口函数解析(九)
最近加班到了一个新的高度,晚上终于有时间了,继续说AppInitParameterInteraction函数的step3。
首先有个华丽的分界线,上面写着Step 3: parameter-to-internal-flags,也就是内部标志使用的参数。
1.内部标志参数
1. DEBUG标志参数
首先确定将哪些目录写入调试日志。
特殊情况:如果设置了 -debug=0 或 -nodebug 参数,则调试日志将关闭。
// *************************************************** *** ********* 第 3 步:parameter-to-internal-flags if (gArgs.IsArgSet("-debug")) {// 特殊情况:if -debug=0/-nodebug is设置,关闭调试信息 const std::vector categories = gArgs. GetArgs("-调试");
if (find(categories.begin(), categories.end(), std::string("0")) == categories.end()) {
for (const auto& cat : categories) {
uint32_t 标志 = 0;
如果 (!GetLogCategory(&flag, &cat)) {
InitWarning(strprintf(_("不支持的日志类别 %s=%s。"), "-debug", cat));
继续;
}
日志类别 |= 标志;
}
}
}
从函数GetLogCategory可以知道,在util.cpp文件的LogCategories数组中记录了所有的类别,如下图,每个类别对应一个编号。
init.cpp中使用的logCategories变量用于记录所有需要调试日志的集合,类型为uint32_t,
上面目录中的每个数字对应32位中的一位,所以每个“|” 操作相当于将当前编号添加到 logCategories 集合中。
// 现在删除明确排除的日志记录类别
对于 (const std::string& cat : gArgs.GetArgs("-debugexclude")) {
uint32_t 标志 = 0;
如果 (!GetLogCategory(&flag, &cat)) {
InitWarning(strprintf(_("不支持的日志记录类别 %s=%s。"), "-debugexclude", cat));
继续;
}
日志类别 &= ~flag;
}
上面的代码起到相反的效果,即从集合中删除当前目录对应的数字,使用“&=~”操作,“~”表示对每一位取反,“&”表示AND操作,上面的反码表示去掉当前目录号。
2. DEBUGNET标志参数
// 检查 -debugnet
如果 (GetBoolArg("-debugnet", false))
InitWarning(_("忽略不支持的参数-debugnet,使用-debug=net。"));
目前比特币网络不支持-debugnet参数,应该使用“-debug=net”代替。
3. SOCKS标志参数
如果(IsArgSet(“-socks”))
return InitError(_("Unsupported argument -socks found. 无法再设置 SOCKS 版本,仅支持 SOCKS5 代理。"));
目前,该程序不支持-socks 参数。 如果设置了,程序会提示初始化错误并退出。
只能设置SOCKS5,那什么是SOCKS5呢? 根据搜狗百科,SOCKS5是一种代理协议。
SOCKS5是一种代理协议,在前端机和服务器机之间使用TCP/IP协议通信起到中介作用,使内网中的前端机可以访问Internet网络中的服务器,或者使通讯更安全。 SOCKS5 服务器通过将请求从前端转发到真实的目标服务器来模拟前端的行为。 这里前端和SOCKS5也是通过TCP/IP协议进行通信的。 前端将原本发往真实服务器的请求发送给SOCKS5服务器,然后SOCKS5服务器再将请求转发给真实服务器。
在向真实服务器发送通信请求的过程中,SOCKS5服务器不会对请求包本身做任何改动。 SOCKS5服务器收到真实服务器的响应后,也原样转发给前端。 因此,SOCKS5协议是一种代理协议,可以适应各种基于TCP/IP的应用层协议,几乎具有通用性。 虽然它不能理解它转发的数据的内部结构,但它可以忠实地转发通信数据包,完成协议原本要完成的功能。
4. TOR 标志参数
如果 (GetBoolArg("-tor", false))
return InitError(_("找到不支持的参数-tor,使用-onion。"));
当前程序不支持-tor参数。 如果设置了,程序将返回一个初始化错误。 应该改用“-onion”。 另外,关于tor(The Onion Router),之前也介绍过。 有兴趣的童鞋可以翻翻之前的文章。 这里我就不细说了。
5. BENCHMARK标记参数
如果 (GetBoolArg("-benchmark", false))
InitWarning(_("忽略不支持的参数 -benchmark,使用 -debug=bench。"));
使用“-benchmark”表示忽略该参数,请使用“-debug=bench”代替。
6. whitelistalwaysrelay 标志参数
如果 (GetBoolArg("-whitelistalwaysrelay", false))
InitWarning(_("忽略不支持的参数 -whitelistalwaysrelay,使用 -whitelistrelay 和/或 -whitelistforcerelay。"));
使用“-whitelistalwaysrelay”表示该参数将被忽略,请使用“-whitelistrelay”或“whitelistforcerelay”代替,或同时使用两者。
7. blockminsize标志参数
如果(IsArgSet(“-blockminsize”))
InitWarning("不支持的参数 -blockminsize 被忽略。");
使用“-whitelistalwaysrelay”提示该参数将被忽略,抱歉,该参数无可替代,消失在茫茫代码中。
2.内存池和块索引检测参数
评论说,Check Mempool和Block Index这两个参数在开发模式下默认设置为true。
// Checkmempool 和 checkblockindex 在 regtest 模式下默认为 true
int ratio = std::min(std::max(GetArg("-checkmempool", chainparams.DefaultConsistencyChecks() ? 1 : 0), 0), 1000000);
如果(比率!= 0){
mempool.setSanityCheck(1.0 / 比率);
}
fCheckBlockIndex = GetBoolArg("-checkblockindex", chainparams.DefaultConsistencyChecks());
fCheckpointsEnabled = GetBoolArg("-检查点", DEFAULT_CHECKPOINTS_ENABLED);
根据帮助信息中的解释,
-checkmempool:指示执行完整性检查的事务数。
-checkblockindex:定时检查mapBlockIndex、setBlockIndexCandidates、chainActive和mapBlockUnlinked变量的一致性。
-checkpoints:该变量默认为true,表示需要校验checkpoint之前的区块信息是否正确; 反之,如果为0,则表示不需要检查,所有检查点信息也存储在chainparams中的checkpointdata中。
完整性检查:表示检查内存池(mempool)中所有交易的一致性,即没有双花,所有输入都是合法的。
代码首先判断chainparams中的DefaultConsistencyChecks是否为真。 如果为 false,ratio 为 0,则不会进行健全性检查。
关于chainparams,在之前发表的文章中也有介绍,主要是根据不同的网络(main、testnet、regtest)为参数选择不同的值。
至于DefaultConsistencyChecks,在main和testnet两种模式下返回值为false。 具体可以进入Chainparams.cpp文件的CMainParams和CTestNetParams类看:fDefaultConsistencyChecks=false,regtest模式的返回值为true,同理可在Chainparams.cpp的CRegTestParams类中看到,也就是说,只有在regtest网络中,默认需要进行一致性检查。
另外函数std::min取两者中的最小值比特币使用了哪种函数,ratio的取值取决于-checkmempool参数值和1000000中的最小值。显然,前者会小于1000000。
tips:关于checkpoints,也就是checkpoints,可以通过以下链接了解:
翻译过来大概意思就是把检查点硬编码到标准客户端中,标准客户端会接受检查点之前发生的所有交易,这些交易会被认为是有效的,不可逆的。 如果有人试图在检查点之前硬分叉一个块,检查点将不会接受分叉。 这将使这些块不可变。 可见其作用是保护比特币网络免受51%攻击。
3.哈希假设有效参数
hashAssumeValid = uint256S(GetArg("-assumevalid", chainparams.GetConsensus().defaultAssumeValid.GetHex()));
如果(!hashAssumeValid。IsNull())
LogPrintf("假设块 %s 的祖先具有有效签名。\n", hashAssumeValid.GetHex());
别的
LogPrintf("正在验证所有区块的签名。\n");
获取hashAssumeValid参数默认值的过程有以下三个步骤:
1.获取链上共识参数
根据chainparams.GetConsensus()可以追溯到chainparams.h文件,其定义如下:
const Consensus::Params& GetConsensus() const { 返回共识; }
Params 是在Params.h 中定义的结构体。 该结构定义了影响链上共识的重要参数。 相信大家看到这些参数的名字都会觉得很寒心。 如下图,有hashGenesisBlock(创世块),nSubsidyHalvingInterval(奖励减半间隔),各种BIP启动高度和hash值,powLimit,fPowAllowMinDifficultyBlocks(工作量证明参数)等,有兴趣的可以自己做自己探索。
2.获取默认假设的有效参数值
当然,上面的结构体还有我们需要的defaultAssumeValid参数。 它的类型是uint256,主要用来存储256位的二进制值。
3.获取哈希值
第三步,通过函数GetHex比特币使用了哪种函数,将得到的值转换成十六进制。
然后通过调用 uint256S 函数将该变量转换为 uint256 对象。
/* 来自 const char * 的 uint256。
* 这是一个单独的函数,因为构造函数 uint256(const char*) 可以产生
* 危险地捕获 uint256(0)。
*/
内联 uint256 uint256S(const char *str)
{
uint256 rv;
房车设置十六进制(海峡);
返回房车;
}
最后,如果 hashAssumeValid 不为空,则假定该块的所有父块都具有有效签名; 否则,需要验证所有区块的签名,并且在这两种情况下都必须记录日志。
区块链研究院比特币源码学习班Jacky