从零到壹学习比特币源码解析第九讲:比特币源码解析-006

黎跃春

孔壹学院、ChainDesk创始人兼CEO

如果您有任何关于区块链的问题,可以加入区块链技术交流QQ群729666975(进群无需添加验证信息,直接点击下一步,等待管理员通过即可),我们会为您一一解答。

从零到壹学习比特币源码解析为一个系列,一共11讲,包括准备知识、源码解析等。今天我们将为大家介绍从零到壹学习比特币源码解析第九讲:比特币源码解析-006。话不多说,马上开启我们的比特币源码解析学习之旅。

课程学习,添加莉莉微信(kongyixueyuan)获取。

孔壹学院

AppInitParameterInteraction

这个函数包括源码中的和两个,主要实现的功能是设置区块链运行时的一些参数。

就在上篇文章中中。

Step 2: parameter interactions

区块修剪参数处理

参数表示启用区块修剪(block pruning),根据bitcoin release note中的描述,

Block pruning allows Bitcoin Core to delete the raw block and undo data once it’s been validated and used to build the databases. At that point, the raw data is used only to relay blocks to other nodes, to handle reorganizations, to look up old transactions (if -txindex is enabled or via the RPC/REST interfaces), or for rescanning the wallet. The block index continues to hold the metadata about all blocks in the blockchain.

区块修剪允许bitcoin core删除raw block和undo data,一旦这些数据已经被验证和更新过数据库。这时候的raw data只能用来转发区块到其他节点、处理区块重组、查看过去的交易(如果启用了-txindex交易索引或者通过RPC/REST接口调用)以及重新扫描钱包。区块索引依然维护所有区块的元数据。

我们知道在比特币运行的本地环境中,有四种类型的数据

raw block从网络中接收的原始区块信息,对应文件为

undo data,在进行chain reorganization时使用的数据,对应文件为。Chain reorganization是指某一个节点发现存在一条比节点当前本地维护的链更长的链,那么该节点就需要进行Chain reorganization,所以这个操作只是针对某一个节点而言的。

block index,区块索引,每一个区块都有一个唯一的索引,对应文件为~/.bitcoin/blocks/index下的.ldblevel db数据库文件。

UTXOUnspent transaction output,表示所有未花费的交易,对应文件为~/.bitcoin/chainstate/中的.ldb文件。

各个系统数据目录:

而删除的就是raw block和undo data两种数据,通过参数N来指定raw block + undo data数据的大小,单位为MB。 N的最小值为550,代表288个区块的大小,按照每个block 10 Min的速率,代表2天的时间。

因为需要删除一些区块的信息,而是对所有交易建立索引,所以这两者不兼容,如果同时设置了,那么则提示错误。

bind 与 listen

这段代码检测和之间的冲突问题,也就是如果设置了的地址而没有设置那么就会报错并退出程序。

文件描述符处理

这段代码主要是确保程序中有足够多的文件描述符,用于程序所需文件,套接字的操作。

常用的几个变量

Step 3: parameter-to-internal-flags

检查 debug 目录

首先的一段代码是判断应该对哪些目录写入调试日志,所有的目录包括以下类型(src/util.cpp line 220),

不支持内部标志参数提示

debug标志参数:主要是标识程序是运行过程中是否输出调试信息,如果-debug=0或者设置了-nodebug参数,则关闭调试信息,并且fDebug=false;(fDebug在src/util.h中声明,在util.cpp中定义);反之如果-debug=1则输出调试信息;

debugnet标志参数:从InitWarning(_("Unsupported argument -debugnet ignored, use -debug=net."));语句我们可以看出比特币程序目前已不支持debugnet参数,需用-debug=net代替;

socks标志参数:从InitError(_("Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported."));语句我们可以看出比特币程序目前已不支持socks参数,对于socket通讯目前只支持SOCKS5代理协议。SOCKS5代理协议又是什么呢?

tor标志参数:tor的英文全称为The Onion Router,即第二代洋葱路由(onion routing),用于匿名通信。关于tor我们在《比特币源码研读之八》中已给出了其具体解释,有兴趣的读者可以前往了解。通过其提示语句InitError(_("Unsupported argument -tor found, use -onion."));,我们可以发现目前已不支持-tor参数,使用-onion参数代替之;

benchmark标志参数:通过其提示语句“InitWarning(_("Unsupported argument -benchmark ignored, use -debug=bench."));”,我们可以知道benchmark已被忽略,使用debug=bench代替之;

whitelistalwaysrelay标志参数:通过其提示语句“InitWarning(_("Unsupported argument -whitelistalwaysrelay ignored, use -whitelistrelay and/or -whitelistforcerelay."));”,我们可以知道whitelistalwaysrelay也已被废弃,转而使用“-whitelistrelay、-whitelistforcerelay”两个参数之一或共同使用来代替之;whitelistrelay参数的意义是节点间的通信优先在白名单节点之接力实现;

blockminsize标志参数:通过其提示语句“InitWarning("Unsupported argument -blockminsize ignored.");”,我们可以知道blockminsize参数也已被废弃,讲不能通过blockminsize参数设置区块中包含信息量的最小值。

交易池与区块索引检测参数

-checkmempool:表示每隔多少个交易进行一次sanity check。

-checkblockindex:每隔一段时间检查mapBlockIndex、setBlockIndexCandidates、chainActive和mapBlockUnlinked变量的一致性。

-checkpoints:该变量默认为1,表示不验证当前已经存在的链;如果为0,表示要检查一些校验点的区块信息是否正确,所有校验点的信息也都保存在chainparams中的checkpointdata中。

代码首先判断 中的是否为 ,如果这个变量为 ,那么ratio=0,也就是不进行sanity check。Sanity check之前在http://blog.csdn.net/pure_lady/article/details/77776716#t2中CTxMemPool类中介绍过,表示检查mempool中所有交易的一致性(没有双花,所有的输入都是合法的)。对于 这个变量的也在http://blog.csdn.net/pure_lady/article/details/77895680中的 函数中介绍过,首先根据设置的网络 、 或者 选择相应的参数,三个网络根据src/chainparams.cpp中给参数定义不同的值,对于 这个参数,MAIN和TESTNET都为 ,而REGTEST中此变量为。

哈希假定有效参数

:表示在blockid之前的所有区块都假设正确的,也就是不用再去验证。如果没有设置,那么就要验证之前所有区块的签名信息。

我们可以看到 参数的默认值可以通过获得,这个默认值的获得过程包括3个步骤:

获得链上共识参数:通过获得链上共识参数,返回类型为,其详细定义我们可以在中找到,Params为一个结构体,该结构体主要定义了影响链上共识的重要参数,比如:创世块(hashGenesisBlock)、奖励减半时间间隔(nSubsidyHalvingInterval)、各种BIP启动时的区块高度、工作量证明参数(powLimit、fPowAllowMinDifficultyBlocks等)、难度调整间隔计算函数(DifficultyAdjustmentInterval)以及默认假定有效对象(defaultAssumeValid);

默认假定有效对象:默认假定有效对象在 中定义 ,其类型是一个类,定义于中,其基类为模板类base_blob,主要用于存储固定大小不透明二进制数值模板,在其后实现了与两个子类,分别实现了160位与256位二进制数值存储类,所以在此处我们可以看到默认假定有效对象主要是需要存储二进制值,而通过base_blob与uint256可以发现该二进制数为区块的哈希值;

获取哈希值:最后一步就是获取哈希值的十六进值,其获取方式通过GetHex()实现。

assumevalid参数的值也可以由用户在命令行中输入,输入形式为包含64位数的十六进制值,其样式如下:

在获得十六进制值后,我们通过uint256S函数将其转换为uint256对象,该函数定义于src/unit256.h中。其函数实现如下:

最后判断hashAssumeValid的有效性,如果不为空,则假定该哈希值对应区块的所有父区块都具备有效的签名,否则需要验证所有区块的签名,并将判断信息输入在日志中。主要在的函数中使用。

交易池大小限定参数

这段代码首先计算mempool的最大值,后面乘以1000000是将单位从MB转换成B,然后计算最小的限制,其中,-limitdescendantsize的含义如下,后面乘以1000将单位从KB转化成B,再乘以40表示最小可以容纳40个这个的交易族。

:如果某个交易在mempool中所有的祖先size之和超过该限制值,那么则拒绝接受该交易。单位为KB。

在上述代码中常量定义于 中,其代表的是交易池最大存储容量(MB)数值,通过其定义我们可以看到其最大容量为300MB。

而交易池最小存储容量对应的默认值为T常量,定义于,其单位为KB,通过其定义我们可以看到其最小存储容量为101KB。

设置脚本验证线程数量

:设置脚本验证线程数量,取值范围为[-2,16],小于0表示令N个保持空闲,0表示自动检测,1表示不允许并行,大于等于2表示同一时刻最大线程数量,默认值为0。

其中MAX_SCRIPTCHECK_THREADS定义的值为16

设置prune保留的文件大小

参数在Step 2中已经介绍过,用来删除已经验证过的区块,取值有以下几种:

0:默认值,表示禁止该功能。

1:表示允许手动使用RPC命令删除旧的区块。

大于等于550:表示允许保存的raw block + undo data文件总大小,其中550MB = MIN_DISK_SPACE_FOR_BLOCK_FILES。

连接超时时间

:表示在发起TCP连接时的等待时间,单位是毫秒,默认值为5000。

节点费用设置

在每个节点内部都可以设置以下几种费用来避免接收过多的交易,

:最小的转发费用,如果交易费小于这个值,节点就直接忽略该交易。默认值为0.00001 BTC/KB。

为区块中打包交易的最小费用值信息,我们可以通过其帮助信息了解到其最低费用通过 中的全局变量进行定义。

:用来判定一笔交易时候是否是dust tx,如果是的话则忽略该交易。默认值为0.00001BTC/KB。

:用来改变mempool最低交易费用的变量,当mempool中的交易数量超过阈值时,交易费用阈值便会增加,增加的程度就由incrementalrelayfee决定。默认值为0.00001BTC/KB。

判断非标准交易

:是否接受或者转发非标准交易,只适用于testnet和regtest,默认值为1.

:设置交易中每个sigop的大小,单位为字节,默认值为20.

接下来就是判断中的参数和参数的值是否相互冲突。是用来计算交易大小的参数,配合,表示交易中操作符的数量,两者的乘积就是交易的大小。

初始化钱包参数&设定交易中数据大小

这段代码首先判断是否启用了钱包,如果启用了,那么就进行钱包参数的初始化,点开函数可以发现,该函数还是比较简单,就是把命令行中相应的参数赋值给中的变量,钱包部分暂且跳过,分析完主要功能部分之后可以再来单独分析钱包的实现。接下来分别设定三个参数,

:是否允许转发non-P2SH多签名,默认值为1。

:表示是否允许在交易中写入数据,默认为1.

:表示交易中写入数据的最大大小,默认值为83.

Initial Block Download

首先模拟时间比较容易理解,就是将当前时间设为0+n秒;接着参数决定是否开启bloom filter服务,该服务的主要功能是按照一定条件过滤某些特定的交易给自己或者其他节点;然后设定序列化版本,具体在何处使用到还的看接下来的分析;最后表示如果当前时间和本地区块链最后一个区块生成的时间差大于那么将执行IBD函数,IBD函数表示要一次性下载大量的区块,具体介绍请参考https://bitcoin.org/en/developer-guide#initial-block-download ,默认值为24小时,也就是说如果节点一天没有更新本地的区块链信息,那么就会执行IBD来从网络同步区块。

:设定系统模拟时间,只适用于regression test,模拟时间表示将时间设置为创世后n秒,即时间从0年0月0日0时0分n秒开始。

:是否支持使用bloom filter来过滤区块和交易,默认为1.

:设置原始交易或者区块在non-verbose模式下的返回值,取值只有两种,0表示non-segwit,1表示segwit,默认值为1.

:执行IBD(Initial block download)的最大时间间隔,单位为秒,默认值为86400,也就是24小时。

mempoolreplacement

所谓交易替换就是指全节点的mempool中如果有多个交易花费了相同的inputs,那么他们之间允许替换。

Regtest测试新deployments

这个参数是用于测试新的功能,所以只用于,首先检测中的参数是否为true,这个参数的含义是让miner在挖到新的block后停止挖矿,直到接到新的命令,而参数在和中都为false,只有在中才为true,函数就是直接返回 变量的值。在命令行中可以指定多个从而同时启用多个新的机制,代码中接下来的for循环就是枚举每一个机制进行处理,输入的形式是,然后分别解析三个参数的值,其中第一个是string类型,后面两个是int64_t类型,解析完之后在系统的deployments表中查找对应名字的机制,系统的deployments表在src/versionbits.cpp中,如下

找到对应的名字之后就通过更新其中的和变量值。

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20180818G1J91Y00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

扫码关注云+社区

领取腾讯云代金券