比特币源码研读系列已完成十二篇了,在前面的十二篇中我们大部分时间是在对传入的参数、定义的全局变量以及代码结构进行了解析,虽然比较繁琐,但是这些内容的研读着实让我对比特币源码中的一些细节有了更深入的理解,掌握了其主要参数所在位置。掌握了这些信息后不管是快速理解后续的源码,还是后续开发自己的区块链产品都可奠定很好的基础。所以,我仍然选择耐着性子稳步对源码进行仔细研读,只有这样才能让自己真正掌握比特币源码,不至于以后还要反复回来重新阅读源码,耗费不必要的时间与精力。同时,也希望大家在看我文章时能提出宝贵意见,一起讨论一起进步。
本文将继续开展应用程序参数交互源码部分(AppInitParameterInteraction)的研读与分析。
本文主要涉及的源码文件包括:
src/bitcond.cpp、src/init.h、src/init.cpp、src/util.h、src/util.cpp、src/validation.h、src/uint256.h、src/policy.h、src/policy.cpp、src/amount.h、src/amount.cpp
一、交易费增长量
交易费增长量(incrementalRelayFee)的默认值在src/policy.h中定义,该值为静态全局变量,其默认值为1000聪,具体定义如下:
/**Default for -incrementalrelayfee, which sets the minimum feerate increase formempool limiting or BIP 125 replacement **/
static const unsigned int DEFAULT_INCREMENTAL_RELAY_FEE = 1000;
incrementalRelayFee为全局变量,其在src/policy.h中声明,并在src/policy.cpp中定义,具体定义如下:
CFeeRate incrementalRelayFee = CFeeRate(DEFAULT_INCREMENTAL_RELAY_FEE);
同时init.cpp中针对incrementalRelayFee的注释如下:
// incremental relay fee sets the minimimum feerateincrease necessary for BIP 125 replacement in the mempool
// and the amount the mempool min fee increases above the feerate of txs evicted due to mempool limiting.
通过其注释我们可以看到incrementalRelayFee的功能是设置最小费率增长量,通过设置交易费增长量与交易最小费的目的考虑交易池的容量限制,排除一些交易费过低的交易,即将其交易退回。
此处还需对incrementalRelayFee做进一步解释,该值可理解为最小交易费用设置的最低值,因为交易池中交易费的增量是以incrementalRelayFee为基础的,所以每笔交易费必须大于等于incrementalRelayFee,也就是说最小交易费也必须大于等于该值。
我们再来看针对incrementalrelayfee参数的处理代码,程序首先通过IsArgSet判断是否设置了incrementalrelayfee参数,如果设置了,则通过ParseMoney函数将输入的以字符串表达的交易增长费转换为数字型的增长交易费,ParseMoney与其反向求解的FormatMoney函数均定义与src/utilmoneystr.h,这两个函数一个是将数字转换为字符串,一个是将字符串转换为数字。
如果传入的金额无效则退出程序,反之为incrementalRelayFee赋值,为其费率值赋予传入的数值:
incrementalRelayFee = CFeeRate(n);
通过CFeeRate(src/amount.h中定义与注释)我们可以知道传入的n的单位为每千字节需要n聪的金额。
二、验证脚本线程数
验证脚本线程数可通过-par参数设置,其线程数获取代码如下:
nScriptCheckThreads = GetArg("-par",DEFAULT_SCRIPTCHECK_THREADS);
通过其注释我们可以看到-par=0时意味着程序自动根据机器情况自动检测线程数,同时如果nScriptCheckThreads==0意味着将不按并发方式实现脚本验证,即脚本验证线程数为0。
默认线程数DEFAULT_SCRIPTCHECK_THREADS在src/validation.h中定义,其默认值为0,意味默认选择自动检测验证线程数。
/**-par default (number of script-checking threads, 0 = auto) */
static const int DEFAULT_SCRIPTCHECK_THREADS = 0;
同时与该宏定义一起定义的还有最大脚本验证线程数常量MAX_SCRIPTCHECK_THREADS,其默认值为16,即程序中最多启动16个线程用于脚本验证操作,其定义如下:
/** Maximum number of script-checking threads allowed*/
static const int MAX_SCRIPTCHECK_THREADS = 16;
我们再来看后面对nScriptCheckThreads的逻辑判断,当nScriptCheckThreads输入值为0或负数时,程序将通过GetNumCores()函数获取程序运行机器能提供的线程数,然后nScriptCheckThreads加上获取的线程数获得脚本验证的线程数。最后是判断nScriptCheckThreads的值:
(1)如果为nScriptCheckThreads<= 1,则nScriptCheckThreads=0;
(2)如果nScriptCheckThreads >MAX_SCRIPTCHECK_THREADS,即验证线程数大于16时,则nScriptCheckThreads赋值为MAX_SCRIPTCHECK_THREADS。
nScriptCheckThreads在src/validation.cpp以及src/init.cpp中使用,src/validation.cpp中主要用于判断是否需要进行脚本验证,使用之处包括
(1)CCheckQueueControl control(fScriptChecks &&nScriptCheckThreads ? &scriptcheckqueue : NULL);
(2)CheckInputs(tx, state, view, fScriptChecks, flags, fCacheResults,txdata[i], nScriptCheckThreads ? &vChecks : NULL)。
而src/init.cpp中则在后面将会研读到的AppInitMain函数中,在该函数中将根据nScriptCheckThreads启动相应数量的线程,其实现代码如下:
LogPrintf("Using %u threads for scriptverification\n", nScriptCheckThreads);
if (nScriptCheckThreads) {
for(int i=0; i
threadGroup.create_thread(&ThreadScriptCheck);
}
通过上面代码我们可以看出,通过线程组创建nScriptCheckThreads个脚本验证线程,线程处理函数为ThreadScriptCheck,其定义于src/validation.h中,实现于src/validation.cpp中,在该函数中通过脚本验证队列管理脚本验证线程,其具体运行方式我们将AppInitMain函数的研读中详细说明。
以上就是本篇文章的研读记录,这篇文章涉及的交易费增长量和验证脚本线程都与比特币中的交易相关,正如《精通比特币》作者在其交易章节说到的“比特币交易是比特币系统中最重要的部分。”,所以,我在写本文的研读记录时对其中的概念进行了多方斟酌、考量与验证,当然也有可能存在理解不到位的情况,大家如果有好的建议可以在留言中给出,我们可以一起讨论,完善我们的研读系列!
区块链研习社比特币源码研读班 菜菜子
以下是我们研习社公众号,欢迎大家订阅并加入我们研习社,一起学习区块链技术
以下是广告:
我们区块链研习社已创建“区块链研习社币圈交流”小密圈”,在小密圈中,我们将带领大家一起学习区块链的原理与投资,还将提供区块链基本原理解答、交易所注册与交易操作、ICO交易与操作、投资分析、风险分析等内容。
目前入圈价格初始定价50元,50人调整一次价格,每次调整幅度为50元!