比特币源码研读之十六

作者: 菜菜子_forest | 来源:发表于2017-09-28 20:15 被阅读1147次

    距离上一篇源码研读记录已有1个多月了,实乃惭愧,本打算每周保持1篇研读记录的节奏的,无奈近期公司业务繁忙,加班甚多,让自己没有保持好研读记录的发表任务。但继续进行源码研读的想法一直在内心中萦绕,时刻提醒自己不能停,一定要抽时间把下一篇研读记录写出来!我不能只看着源码研读班的同学们发表记录,自己却没有文章输出!所以今天重新坐在电脑前重启我的源码研读之旅,开启我的第十六篇源码研读之旅。

    本文将继续开展应用程序参数交互源码部分(AppInitParameterInteraction)的研读与分析。

    本文主要涉及的源码文件包括:

    src/bitcond.cpp、src/init.h、src/init.cpp、src/util.h、src/wallet/wallet.h、src/wallet/wallet.cpp、src/net、src/validation.h、src/validation.cpp

    本文主要对钱包交互参数源码的分析,这部分代码是否执行要看比特币程序是否启用了钱包功能,其是否启动依赖于ENABLE_WALLET宏定义变量,其判断代码如下:

    #ifdef ENABLE_WALLET

    if (!CWallet::ParameterInteraction())

    return false;

    #endif

    其中ENABLE_WALLET宏定义开关在configure.ac文件中,也就是说,我们可以在源码编译的时候就可以控制该宏定义的开关。其具体设置如下图所示:

    从图中我们可以看出默认是打开钱包功能的,我们也可以在运行比特币客户端时通过—disablewallet参数关闭钱包功能。

    再回到刚才的代码,如果比特币程序启用了钱包功能,那么与钱包相关的交互参数必须设置正确,否则程序将终止运行。其涉及的参数较多,我们在本文将对ParameterInteraction静态函数中涉及的参数进行逐个分析。

    一、禁止钱包功能参数

    ParameterInteraction函数的第一个判断的参数为-disablewallet,其判断代码如下:

    if (GetBoolArg("-disablewallet",DEFAULT_DISABLE_WALLET))

    return true;

    DEFAULT_DISABLE_WALLET宏定义在src/wallet/wallet.h中定义,其默认值为false,也就是说默认是打开钱包功能的,但如果我们在运行时设置了-disablewallet参数,我们的钱包功能将被关闭,将不会加载钱包,同时禁用钱包的RPC调用,程序也将返回,并停止运行。

    二、blocksonly参数

    blocksonly参数为比特币客户端以调试状态启动时才会使用的,这点我们可以从src/init.cp的HelpMessage函数中获取到其帮助信息:

    if (showDebug)

    strUsage += HelpMessageOpt("-blocksonly",strprintf(_("Whether to operate in a blocks only mode (default:%u)"), DEFAULT_BLOCKSONLY));

    此处的默认参数DEFAULT_BLOCKSONLY在src/net.h中定义,具体定义如下:

    /** Default for blocks only*/

    static const bool DEFAULT_BLOCKSONLY =false;

    我们可以看到其默认条件下为false,即默认不会只以区块模式运行,因为如果在区块模式下运行,全网的交易将不会被打包,钱包的交易广播功能将失效,也就是我们看到的walletbroadcast参数此时需要设置为false,否则将会互斥。

    三、salvagewallet参数

    salvagewallet参数的功能为试图在比特币客户端启动时从损坏的钱包中恢复私钥。通过日志打印代码:

    LogPrintf("%s: parameter interaction:-salvagewallet=1 -> setting -rescan=1\n", __func__);

    我们可以看出该参数只有用-rescan参数启动客户端的情况下才能生效。

    四、zapwallettxes参数

    zapwallettxes参数用于删除钱包的所有交易记录,且只有用-rescan参数启动客户端才能重新取回交易记录,且只有用-rescan参数启动客户端才能重新取回交易记录(mode=1时保留tx meta data ,如account owner和payment request information, mode=1时不保留tx meta data)。

    五、sysperms参数

    该参数已经在《比特币源码研读之九》中进行了解释,其含义此处不再赘述。我们通过其后面的错误提示信息:

    -sysperms is not allowed in combinationwith enabled wallet functionality

    可以看出该参数在具备钱包功能时是不能用-sysperms参数的,否则二者将会冲突,程序自动退出。

    六、prune与rescan参数

    该参数已经在《比特币源码研读之九》中进行了解释,其含义此处不再赘述。我们通过其后面的错误提示信息:

    Rescans are not possible in pruned mode.You will need to use -reindex which will download the whole blockchain again.

    可以看出该参数在比特币客户端使用rescan参数启动时,是不能用prune参数的,否则二者将会冲突,程序自动退出。

    以上6类参数均为考虑在启动钱包功能时,一些参数之间的冲突处理,后面我们将涉及交易与交易费用相关的参数处理。

    七、minRelayTxFee

    minRelayTxFee为全局变量,其在src/validation.h中声明,并且在src/validation.cpp中完成定义,我们已经在《比特币源码研读之十五》中对其进行了详细分析,此处不再赘述。我们通过代码来看minRelayTxFee在此处的用途:

    if (::minRelayTxFee.GetFeePerK()> HIGH_TX_FEE_PER_KB)

    InitWarning(AmountHighWarn("-minrelaytxfee")+ " " +

                   _("The wallet will avoid paying less than the minimum relay fee."));

    我们首先来看这段代码中代表最高手续费的宏定义HIGH_TX_FEE_PER_KB,该宏在src/validation.h中定义:

    //! Discourageusers to set fees higher than this amount (in satoshis) per kB

    static constCAmount HIGH_TX_FEE_PER_KB = 0.01 * COIN;

    其中COIN在src/amount.h中定义,具体定义如下:

    staticconst CAmount COIN = 100000000;

    从定义我们可以看出COIN为1亿,即代码1个比特币的数量。进而我们可以知道HIGH_TX_FEE_PER_KB代表手续费最高为0.01个比特币,超过这个值系统将会提示出错。

    而比特币转账是需要手续费的,而且可以由用户自定义设置,但其设置的手续费是不能低于最低手续费,也不能高于最高手续费的。从这我们就可以理解此处的if判断语句的用途了,其目的是防止用户设置的最低手续费高于比特币程序中设置的最高手续费,导致手续费过高,影响比特币网络的正常运转。

    八、mintxfee

    此处的mintxfee参数判断与minRelayTxFee参数的处理基本一致,最低手续费不应高于最高手续费,否则程序将给出警告提示。

    九、fallbackfee

    fallbackfee的具体用途我们通过当前的代码应该是不清楚的,但我们可以在wallet.cpp文件的多个地方查找关于这个参数的注释:

    (1)wallet.cpp的初始位置

    /**

    * Iffee estimation does not have enough data to provide estimates, use this feeinstead.

    *Has no effect if not using fee estimation

    *Override with -fallbackfee

    */

    CFeeRate CWallet::fallbackFee =CFeeRate(DEFAULT_FALLBACK_FEE);

    (2)GetWalletHelpString函数

    strUsage +=HelpMessageOpt("-fallbackfee=", strprintf(_("A feerate (in %s/kB) that will be used when fee estimation has insufficient data (default:%s)"),CURRENCY_UNIT,FormatMoney(DEFAULT_FALLBACK_FEE)));

    在这个函数中我们可以看到fallbackfee参数的帮助信息,其翻译过来的意思是当没有足够的数据供程序估算费用的时候,将默认使用fallbackfee,而这个参数的默认值为,该参数的默认值DEFAULT_FALLBACK_FEE在src/wallet/wallet.h中定义:

    //! -fallbackfee default

    static const CAmount DEFAULT_FALLBACK_FEE =20000;

    估算费用存储在数据目录的fee_estimates.dat文件中,如图所示:

    (3)GetMinimumFee函数佐证

    // ... unless we don't have enough mempooldata for estimatefee, then use fallbackFee

    if(nFeeNeeded == 0)

    nFeeNeeded= fallbackFee.GetFee(nTxBytes);

    通过其注释我们也可以看出当交易池中没有足够数据支撑手续费的估算时,就使用fallbackFee作为较低最低收费费。

    十、paytxfee与maxtxfee

    paytxfee与maxtxfee代表的分别是支付交易手续费与最高交易手续费,此处主要判断二者是否在最高低手续费与最高手续费之间,如果最低手续费则程序退出,高于最高手续费将给出警告,提示您给多了,超出了最高手续费。

    十一、txconfirmtarget

    相信大家应该都知道比特币的每一笔交易都需要经过6次区块确认才能算真正的交易成功了,且不能回退,而这个确认值是怎么来的呢?经过我们长途跋涉的源码研读,今天终于看到了,就是我们现在要介绍的txconfirmtarget参数。我们看到该参数的默认参数为DEFAULT_TX_CONFIRM_TARGET,该宏定义在src/wallet/wallet.h中,具体如下:

    //! -txconfirmtarget default

    static const unsigned intDEFAULT_TX_CONFIRM_TARGET = 6;

    我们看到了它的值默认为6!其实我们也可以在启动客户端时通过txconfirmtarget参数进行修改其确认数为其他值,但为了全网一致,大家很少做这方面的修改。

    十二、spendzeroconfchange

    spendzeroconfchange参数的作用是表示比特币客户端是否可以花费0确认的费用,在0.14版其默认是允许的,因为其默认参数在src/wallet/wallet.h中定义:

    static const boolDEFAULT_SPEND_ZEROCONF_CHANGE = true;

    即其默认为true,允许花费0确认的费用。

    十三、sendfreetransactions

    sendfreetransactions参数的含义是是否发送0手续费的交易,默认为不可以发送0手续费的交易,其默认参数为DEFAULT_SEND_FREE_TRANSACTIONS,其在src/wallet/wallet.h中定义,其定义如下:

    //! Default for -sendfreetransactions

    static const bool DEFAULT_SEND_FREE_TRANSACTIONS = false;

    我们看到其默认值为false,也就是说不能发送0手续费的交易。

    十四、walletrbf

    Bitcoin Core 0.14.0开启了一项可选的功能(默认为禁用):

    src/wallet/wallet.h中的定义

    static const bool DEFAULT_WALLET_RBF = false;

    它可以为钱包产生的所有新交易添加交易费,具体是指BIP125可选费用替代法(RBF)。

    想要启用该功能,可以在Bitcoin Core客户端用-walletrbf启用,这一功能可为先前未确认的交易添加手续费,以加大交易被确认的机会。支持opt-in RBF或者full RBF功能的矿工通常会在他们的交易处理队列中放入更高费用的交易,而更高的交易费将鼓励矿工更快地挖取新版本的交易。

    十五、limitfreerelay

    limitfreerelay参数的注释我们可以从src/init.cpp中的HelpMessage函数中获取,其具体解释如下:

    strUsage+=HelpMessageOpt("-limitfreerelay=",strprintf("Continuously rate-limit free transactions to *1000

    bytes per minute (default: %u)", DEFAULT_LIMITFREERELAY));

    通过其注释我们可以看到limitfreerelay参数表示的含义是其每分钟可连续广播的免费交易数,其大小为默认的DEFAULT_LIMITFREERELAY个千字节量。

    此处代码为:

    if(fSendFreeTransactions&&GetArg("-limitfreerelay",DEFAULT_LIMITFREERELAY) <= 0)

           return InitError("Creation of free transactions with their relay disabled is notsupported.");

    即如果允许发送免费交易,那么limitfreerelay不能为0,如果为0则表示不能广播免费交易,程序给出错误提示。

    至此我们完成了CWallet::ParameterInteraction()函数的解析,即完成了钱包交互参数的解析。我们对钱包相关的参数有了更进一步的理解,在运行比特币客户端时,我们也能按照我们自己的需求设置相应的参数值,玩转比特币客户端钱包功能,当然在玩转之前我们需要先有可运行的客户端,客户端得到呢?我们可以自己编译,如何编译?推荐大家参考我们研习社比特币编程系列中的《比特币源码编译》课程,跟着课程我们可以完成客户端的编译,并运行客户端,设置我们个性化的钱包,还等什么呢?行动起来吧!

    相关文章

      网友评论

      • sunny嘴甜甜:推荐一款好玩的区块链产品,下载填邀请码注册即送币哦。
        【数十万人下载的首款全民参与区块链APP——有令,注册就送数字资产YOU,邀请还能再送5000】https://you.ihuanqu.com/download.html 复制链接在浏览器里打开。我的邀请码:9AHJ
      • OYohoo:limitfreerelay参数 0.15这个版本取消了
      • OYohoo:ParameterInteraction函数的第一个判断的参数为-disablewallet,改为这种比较容易理解和找到到:WalletParameterInteraction()方法在wallet\init.cpp中实现,第一个判断的参数为-disablewallet
      • yikekuteng:研读九:
        sysperms:在创建新文件时,文件权限为系统默认权限,以此来代替umask 077命令(因为umask 077只在钱包功能被禁止时才其作用)

        本章:
        可以看出该参数在具备钱包功能时是不能用-sysperms参数的,否则二者将会冲突,程序自动退出。

        这两个描述互相矛盾?
        yikekuteng:我理解错误了。禁用钱包时,才能设置-sysperms参数,我理解为才能设置为true了。
        菜菜子_forest:@yikekuteng ,没有啊,二者是互斥的啊

      本文标题:比特币源码研读之十六

      本文链接:https://www.haomeiwen.com/subject/cmmvextx.html