本篇文章涉及的文件有:
init.cpp、wallet.cpp、policy.cpp
我们接着上篇内容继续分析方法AppInitParameterInteraction().在此之前,大家可以从https://bitcoin.org/en/developer-guide#non-standard-transactions 学习到比特币中有关标准交易(Standard Transaction)以及非标准交易(Non-standard Transaction)的定义,主要根据交易中包含的信息是否是有效的且已经定义好的,如锁定脚本与解锁脚本中是否包含了没有定义的脚本命令等,判断一个交易是否是标准交易封装在函数policy.cpp中的IsStandardTx ()方法中,我们后续将具体分析该函数的内容。
可以通过参数acceptnonstdtxn来指定节点是否接受非标准交易。在文件chainparams.cpp中可以看到,只有主网络的参数fRequireStandard设置为true, 而Test和Reg网络为false,从下面的代码可以看出,如果在启动主网络的节点设置acceptnonstdtxn为false,是会抛出异常的。
fRequireStandard = !gArgs.GetBoolArg("-acceptnonstdtxn", !chainparams.RequireStandard());
if (chainparams.RequireStandard() && !fRequireStandard)
return InitError(strprintf("acceptnonstdtxn is not currently supported for %s chain",
chainparams.NetworkIDString()));
下面的参数-bytespersigop用于policy.cpp的函数GetVirtualTransactionSize中计算交易的大小,默认值为20(衡量每个操作符大小,用于交易手续费的计算???后续需再研究该参数的具体作用)。
nBytesPerSigOp = gArgs.GetArg("-bytespersigop", nBytesPerSigOp);
int64_t GetVirtualTransactionSize(int64_t nWeight, int64_t nSigOpCost)
{
return (std::max(nWeight, nSigOpCost * nBytesPerSigOp) + WITNESS_SCALE_FACTOR - 1) / WITNESS_SCALE_FACTOR;
}
如果节点开启了钱包服务,则需要设置与钱包相关的参数。
#ifdef ENABLE_WALLET
if (!CWallet::ParameterInteraction())
return false;
#endif
我们接下来将通过分析函数ParameterInteraction看下都有哪些和钱包服务相关的参数需要设置。
gArgs.SoftSetArg("-wallet", DEFAULT_WALLET_DAT);//设置默认的钱包文件名称wallet.dat
const bool is_multiwallet = gArgs.GetArgs("-wallet").size() > 1;//是否设置了多个-wallet值
if (gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET))//是否设置不启用钱包服务
return true;
用户可以选择加入区块链网络的参与度,如可以通过参数blocksonly设置不进行交易的获取和转发来减少带宽占用。
if (gArgs.GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY) && gArgs.SoftSetBoolArg("-walletbroadcast", false)) {
LogPrintf("%s: parameter interaction: -blocksonly=1 -> setting -walletbroadcast=0\n", __func__);
}
节点程序有时候会运行出现故障等导致程序不能正常工作的问题,当钱包节点出现故障时,可以通过参数salvagewallet尝试恢复之前的公私钥对。
if (gArgs.GetBoolArg("-salvagewallet", false)) {
if (is_multiwallet) {//如果通过参数salvagewallet进行恢复,只能指定单个钱包文件进行
return InitError(strprintf("%s is only allowed with a single wallet file", "-salvagewallet"));
}
// Rewrite just private keys: rescan to find transactions
if (gArgs.SoftSetBoolArg("-rescan", true)) {//重新扫描区块链,找到恢复后相关的交易
LogPrintf("%s: parameter interaction: -salvagewallet=1 -> setting -rescan=1\n", __func__);
}
}
有时候我们会遇到交易经过很长时间都没有被打包(如:交易手续费设置的太低),我们可以通过参数zapwallettxes尝试进行取消原有的交易。设置zapwallettxes=1会将本地节点中所有未打包的交易清空,同时默认会进行一个rescan。rescan完成后,重新发起一笔交易,使该交易包含了之前未被打包的交易所使用的UTXO。待该交易广播到网络进行打包,因为双花的检查,原有的交易将会被抛弃(参考:http://cryptomining-blog.com/tag/zapwallettxes/)。
int zapwallettxes = gArgs.GetArg("-zapwallettxes", 0);
// -zapwallettxes implies dropping the mempool on startup//启动时情况内存池
if (zapwallettxes != 0 && gArgs.SoftSetBoolArg("-persistmempool", false)) {
LogPrintf("%s: parameter interaction: -zapwallettxes=%s -> setting -persistmempool=0\n", __func__, zapwallettxes);
}
// -zapwallettxes implies a rescan//进行rescan
if (zapwallettxes != 0) {
if (is_multiwallet) {
return InitError(strprintf("%s is only allowed with a single wallet file", "-zapwallettxes"));
}
if (gArgs.SoftSetBoolArg("-rescan", true)) {
LogPrintf("%s: parameter interaction: -zapwallettxes=%s -> setting -rescan=1\n", __func__, zapwallettxes);
}
}
随着比特币程序的升级,钱包文件的格式也会有更新,可以通过-upgradewallet参数设置进行钱包文件的升级操作,不过升级过程只支持一个钱包文件的情况(为什么不能支持多个,后续分析过程中应该会有答案)。
if (is_multiwallet) {
if (gArgs.GetBoolArg("-upgradewallet", false)) {//升级钱包文件wallet.dat的格式
return InitError(strprintf("%s is only allowed with a single wallet file", "-upgradewallet"));
}
}
可以通过参数sysperms控制是否已系统默认权限创建文件,但是在开启钱包功能的节点是不能启用的(详细请参考:http://www.jianshu.com/p/d42558e7e8e8).
if (gArgs.GetBoolArg("-sysperms", false))
return InitError("-sysperms is not allowed in combination with enabled wallet functionality");
之前的文章我们分析过prune和rescan的作用,一个是裁剪一个是重建交易,两者是互斥的。
if (gArgs.GetArg("-prune", 0) && gArgs.GetBoolArg("-rescan", false))
return InitError(_("Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again."));
用户是可以设置交易费率的,程序为保证用户的权益,当交易费率设置的很高时会给出相应的提示。设置的交易费率minRelayTxFee和mintxfee如果高于默认的最高交易费率HIGH_TX_FEE_PER_KB(0.01btc),给给出警告信息。
if (::minRelayTxFee.GetFeePerK() > HIGH_TX_FEE_PER_KB)
InitWarning(AmountHighWarn("-minrelaytxfee") + " " +
_("The wallet will avoid paying less than the minimum relay fee."));
if (gArgs.IsArgSet("-mintxfee"))
{
CAmount n = 0;
if (!ParseMoney(gArgs.GetArg("-mintxfee", ""), n) || 0 == n)
return InitError(AmountErrMsg("mintxfee", gArgs.GetArg("-mintxfee", "")));
if (n > HIGH_TX_FEE_PER_KB)
InitWarning(AmountHighWarn("-mintxfee") + " " +
_("This is the minimum transaction fee you pay on every transaction."));
CWallet::minTxFee = CFeeRate(n);
}
当交易估算交易费率的数据不足时,将采用fallbackfee的值作为交易费率的默认值,同样如果该值超过了HIGH_TX_FEE_PER_KB也会收到警告。
if (gArgs.IsArgSet("-fallbackfee"))
{
CAmount nFeePerK = 0;
if (!ParseMoney(gArgs.GetArg("-fallbackfee", ""), nFeePerK))
return InitError(strprintf(_("Invalid amount for -fallbackfee=<amount>: '%s'"), gArgs.GetArg("-fallbackfee", "")));
if (nFeePerK > HIGH_TX_FEE_PER_KB)
InitWarning(AmountHighWarn("-fallbackfee") + " " +
_("This is the transaction fee you may pay when fee estimates are not available."));
CWallet::fallbackFee = CFeeRate(nFeePerK);
}
好了,本篇文章就先分析到这。因本人水平有限,如有问题,欢迎大家批评指出,非常感谢。