比特币源码研读之十一
比特币源码研读系列已经发表了十篇了,通过这十篇源码研读系列让我对比特币源码及比特币运行原理有了进一步的理解,也让我不论是在技术层面,还是读者人气都有了很多的收获。这些都是鼓励我继续前行的动力。其实在开始准备本篇文章初期,我在继续看比特币源码时,发现难度开始有点提升了,有些参数和实现开始变得不好理解了,心中确实出现了点退却的心理,因为担心自己的理解出错,误导了读者!但笑来老师这周的文章刚好是关于执行力的,从他的文章让我知道,不会的去学就好了,学会了再来做,直到做成为止,就这么简单,一定不能让自己成为不了了之之人!于是我好像又有能量了,开始沉下心来继续研读源码。相信在后面的研读过程中也将遇到很多问题,我不断提升执行力,继续努力突破困难,让自己成长起来,将我自己的研读成果分享给大家,与大家共同进步!
本文将继续开展应用程序参数交互源码部分(AppInitParameterInteraction)的研读与分析。
本文主要涉及的源码文件包括:
src/bitcond.cpp、src/util.h、src/util.cpp、src/init.h、src/init.cpp、src/net.h、src/validation.h、src/txmempool.h
一、不支持内部标志参数提示
在Step 3: 内部标志(flags)参数的最开始部分,比特币核心源码主要是对标志参数的有效性进行判断,并作出警告或错误退出处理。具体处理的参数、处理顺序以及处理方法见流程图。
(1)debug标志参数:主要是标识程序是运行过程中是否输出调试信息,如果-debug=0或者设置了-nodebug参数,则关闭调试信息,并且fDebug=false;(fDebug在src/util.h中声明,在util.cpp中定义);反之如果-debug=1则输出调试信息;
(2)debugnet标志参数:从InitWarning(_("Unsupported argument -debugnet ignored, use -debug=net."));语句我们可以看出比特币程序目前已不支持debugnet参数,需用-debug=net代替;
(3)socks标志参数:从InitError(_("Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported."));语句我们可以看出比特币程序目前已不支持socks参数,对于socket通讯目前只支持SOCKS5代理协议。SOCKS5代理协议又是什么呢?
百度百科的解释如下:
SOCKS5是一个代理协议,它在使用TCP/IP协议通讯的前端机器和服务器机器之间扮演一个中介角色,使得内部网中的前端机器变得能够访问Internet网中的服务器,或者使通讯更加安全。SOCKS5服务器通过将前端发来的请求转发给真正的目标服务器,模拟了一个前端的行为。在这里,前端和SOCKS5之间也是通过TCP/IP协议进行通讯,前端将原本要发送给真正服务器的请求发送给SOCKS5服务器,然后SOCKS5服务器将请求转发给真正的服务器。
SOCKS像一堵墙被夹在Internal服务器和客户端之间,对于出入企业网络的资讯提供流量和安全的管理。
从以上解释我们可以看出使用SOCKS代理协议的主要目的是提高网络通信的安全性。
(4)tor标志参数:tor的英文全称为The Onion Router,即第二代洋葱路由(onion routing),用于匿名通信。关于tor我们在《比特币源码研读之八》中已给出了其具体解释,有兴趣的读者可以前往了解。通过其提示语句InitError(_("Unsupported argument -tor found, use -onion."));,我们可以发现目前已不支持-tor参数,使用-onion参数代替之;
(5)benchmark标志参数:通过其提示语句“InitWarning(_("Unsupported argument -benchmark ignored, use -debug=bench."));”,我们可以知道benchmark已被忽略,使用debug=bench代替之;
(6)whitelistalwaysrelay标志参数:通过其提示语句“InitWarning(_("Unsupported argument -whitelistalwaysrelay ignored, use -whitelistrelay and/or -whitelistforcerelay."));”,我们可以知道whitelistalwaysrelay也已被废弃,转而使用“-whitelistrelay、-whitelistforcerelay”两个参数之一或共同使用来代替之;whitelistrelay参数的意义是节点间的通信优先在白名单节点之接力实现;
(7)blockminsize标志参数:通过其提示语句“InitWarning("Unsupported argument -blockminsize ignored.");”,我们可以知道blockminsize参数也已被废弃,讲不能通过blockminsize参数设置区块中包含信息量的最小值。
二、交易池与区块索引检测参数
通过注释“// Checkmempool and checkblockindex default to true in regtest mode(检测交易池和区块索引,这两个参数在私有网模式(也可理解为开发模式)下默认为true,即默认执行检测)”以及后面的代码,我们可以发现checkmempool与checkblockindex在开发模式下是肯定会执行的,其目的是为了比特币在正式运行前确保交易状态与区块索引的正确性。作为开发人员,我们可以很容易理解到,检测程序来说是存在资源消耗的,从而会影响程序的运行效率,那么在测试网模式与主网模式下,这两个参数是默认为false的。
(1)交易池参数检测
我们首先来看交易池参数检测处理代码如下:
int ratio = std::min(std::max(GetArg("-checkmempool",chainparams.DefaultConsistencyChecks() ? 1 : 0), 0),1000000);
if (ratio != 0) {
mempool.setSanityCheck(1.0 / ratio);
}
上述源码中,我们首先来看mempool对象,定义于src/validation.h中,其类型为CTxMemPool类,该类在src/txmempool.h中定义,其主要用途是存储主链中发生的有效交易,这些交易也将会被打包至后续的区块中。但如下条件下的交易是不会加入到交易池中的:
1)交易所给出的交易费未达到最小交易费;
2)存在“双花”的交易,即矿池中已包含该交易;
3)非标准交易。
正因为有了上述3个条件,所以CTxMemPool会对交易进行完整性检测,检测的频率通过setSanityCheck函数来设置,该函数的实现内容如下:
void setSanityCheck(double dFrequency = 1.0) { nCheckFrequency = dFrequency * 4294967295.0; }
其中,4294967295=2^32次方-1,此处的nCheckFrequency代表交易池中所有交易的检测频率,即每nCheckFrequency隔多少个交易检测一次。此处以4294967295为基数设置检测频率。
那我们在来看传入的dFrequency值是如何计算的。在init.cpp中,dFrequency的值是1.0/ratio,ratio的计算是在如下代码实现的:
int ratio = std::min(std::max(GetArg("-checkmempool",chainparams.DefaultConsistencyChecks()? 1 : 0), 0), 1000000);
这里需要关注的是chainparams.DefaultConsistencyChecks(),chainparams是在const CChainParams& chainparams = Params();中获取,其具体实现的解读可在《比特币源码研读之六》中详细了解。这里要说的是chainparams根据传入的命令参数(默认为主网),其有可能是主网、测试网或私有网3种对象之一。而这3种模式下DefaultConsistencyChecks获取的值是不一样的,在主网、测试网中其返回值为false(见Chainparams.cpp的CMainParams与CTestNetParams类中fDefaultConsistencyChecks=false),私有网的返回值为true(见Chainparams.cpp的CRegTestParams类中fDefaultConsistencyChecks=true)。即只有在私有网中才默认需要进行一致性检测。
而ratio值则是根据-checkmempool传入的参数值与1000000之间的最小值而定的,它们的比较取值用的是std::min,即ratio的值取二者中最小者,我们也可以看出其值不会超过1000000。
(2)区块索引检测
区块索引参数处理也很简单,其实现代码如下:
fCheckBlockIndex =GetBoolArg("-checkblockindex",chainparams.DefaultConsistencyChecks());
从其代码我们可以看出,只有在私有网模式下才会进行区块索引的检测,其他两个网默认是不检测的。
fCheckBlockIndex参数定义于src/validation.h中,该变量为全局变量,所以可在init.cpp中根据“checkblockindex”参数进行修改。进而在validation.cpp中的CheckBlockIndex函数中使用该变量,在这个函数中如果checkblockindex为true,将实现了区块索引信息的验证,具体验证内容我们将在后续的研读文章中详细记录。
以上就是本次研读的内容,在这篇研读文章中我们知道了SOCKS5代理协议、用于匿名通信的第二代洋葱路由(onion routing)、交易池以及区块索引等概念,让我们对比特币源码的内在实现有了进一步的理解!我相信后续会有更多值得我们去探索与理解的新概念,敬请期待吧!
区块链研习社比特币源码研读班 菜菜子
以下是广告:
我们区块链研习社已创建“区块链研习社币圈交流”小密圈”,在小密圈中,我们将带领大家一起学习区块链的原理与投资,还将提供区块链基本原理解答、交易所注册与交易操作、ICO交易与操作、投资分析、风险分析等内容。
目前入圈价格初始定价50元,50人调整一次价格,每次调整幅度为50元!