上文介绍了读取配置文件函数ReadConfigFile。
try
{
gArgs.ReadConfigFile(gArgs.GetArg("-conf", BITCOIN_CONF_FILENAME));
}
catch (const std::exception& e)
{
fprintf(stderr,"Error reading configuration file: %s\n", e.what());
return false;
}
当读取配置文件ReadConfigFile失败时,将进入catch,并打印错误信息,函数返回。
下面我们讲解参数配置。
一,获取网络参数
先介绍一点比特币知识:比特币网络分为主网、测试网以及私有网三种网络,其中主网就是我们现在使用的正式运行的可进行实际交易的网络,在其上我们可以实现物品的交易与服务;测试网顾名思义即为公共测试网络,因为其实测试网,所以,其上的信息是可以重设的;私有网的难度很低,很容易产生块,所以开发者一般在私有网中开展应用的开发与自测试。三个网络的的英文名分别为:
主网:Main network
测试网:Testnet
私有网:Regressiontest
下面我们看代码
// Check for-testnet or -regtest parameter (Params() calls are only valid after thisclause)
try {
SelectParams(ChainNameFromCommandLine());
} catch (const std::exception& e) {
fprintf(stderr, "Error:%s\n", e.what());
return false;
}
注释中提到,要先检查是testnet还是regtext参数,testnet就是测试网络,regtest就是私有网络。
代码中,使用try catch异常处理机制实现比特币的网络设置工作(try catch的介绍见C++异常处理)。
函数SelectParams的输入参数是函数ChainNameFromCommandLine的返回值。那ChainNameFromCommandLine函数是什么呢?返回值又是什么呢?ChainNameFromCommandLine函数的定义在文件chainparamsbase.cpp下,其函数实现如下:
std::string ChainNameFromCommandLine()
{
bool fRegTest =gArgs.GetBoolArg("-regtest", false);
bool fTestNet =gArgs.GetBoolArg("-testnet", false);
if (fTestNet&& fRegTest)
throwstd::runtime_error("Invalid combination of -regtest and -testnet.");
if (fRegTest)
returnCBaseChainParams::REGTEST;
if (fTestNet)
returnCBaseChainParams::TESTNET;
return CBaseChainParams::MAIN;
}
GetBoolArg(const std::string& strArg, bool fDefault)函数,判断是否为strArg,如果是则返回true,如果不是则返回false。
ChainNameFromCommandLine函数流程图如下:
1,首先获取fRegTest与fTestNet参数。
2,如果两个参数都设置了,因为一个比特币程序不可能同时存在两个网络,所以,程序将异常退出,同时抛出异常错误,由之前的try catch模块处理,打印异常错误提示信息;
3,MAIN,TESTNET,REGTEST是静态变量,定义如下:
const std::string CBaseChainParams::MAIN = "main";//主网
const std::string CBaseChainParams::TESTNET = "test";//测试网
const std::string CBaseChainParams::REGTEST = "regtest";//私有网
4,如果设置了私有网,则返回,CBaseChainParams::REGTEST
5,如果设置了测试网,则返回,CBaseChainParams::TESTNET
6,如果都没设置,则返回主网,CBaseChainParams::MAIN
二,网络参数设置
当获得了网络参数以后,将参数传给函数SelectParams,函数在文件chainparams.cpp中,其函数实现如下:
void SelectParams(const std::string& network)
{
SelectBaseParams(network);//设置globalChainBaseParams
globalChainParams= CreateChainParams(network);//设置globalChainParams
}
其中有两个函数,SelectBaseParams(network)与CreateChainParams(network)
函数SelectBaseParams(network)在chainparamsbase.cpp中实现,函数实现如下
void SelectBaseParams(const std::string& chain)
{
globalChainBaseParams = CreateBaseChainParams(chain);
}
可以看出,这两个函数:
CreateBaseChainParams(chain);返回globalChainBaseParams
CreateChainParams(network),返回globalChainParams;
两个函数的实现基本是一致的,CreateBaseChainParams是设置网络端口等基础参数,CreateChainParams是设置链路的主要参数
1)设置globalChainBaseParams网络参数(网络端口等基本参数)
调用函数SelectBaseParams(network),这个函数定义在chainparamsbase.cpp中,其函数实现如下:
void SelectBaseParams(const std::string& chain)
{
globalChainBaseParams = CreateBaseChainParams(chain);
}
该函数调用了函数CreateBaseChainParams(chain),这个函数也定义在chainparamsbase.cpp文件中,其函数实现如下:
std::unique_ptrCreateBaseChainParams(const std::string& chain)
{
if (chain ==CBaseChainParams::MAIN)
returnstd::unique_ptr(new CBaseMainParams());
else if (chain ==CBaseChainParams::TESTNET)
returnstd::unique_ptr(new CBaseTestNetParams());
else if (chain ==CBaseChainParams::REGTEST)
returnstd::unique_ptr(new CBaseRegTestParams());
else
throw std::runtime_error(strprintf("%s:Unknown chain %s.", __func__, chain));
}
其中的CBaseChainParams是一个类定义,定义如下:
/**
* CBaseChainParamsdefines the base parameters (shared between bitcoin-cli and bitcoind) * of agiven instance of the Bitcoin system.
*/
class CBaseChainParams
{
public:
/** BIP70 chainname strings (main, test or regtest) */
static conststd::string MAIN;
static conststd::string TESTNET;
static conststd::string REGTEST;
conststd::string& DataDir() const { return strDataDir; }
int RPCPort()const { return nRPCPort; }
protected:
CBaseChainParams() {}
int nRPCPort;
std::stringstrDataDir;
};
看其注释,可以知道,这个类定义了比特币客户端的一些基本参数
CreateBaseChainParams函数的流程图如下:
1.如果输入参数是主链MAIN,则创建并一个主链类CBaseMainParams
2.如果输入参数是测试链TESTNET,则创建并一个主链类CBaseTestNetParams
3.如果输入参数是私有链REGTEST,则创建并一个主链类CBaseRegTestParams
4,如果都不是,则打印消息,提示错误。
CBaseMainParams()函数如下:
class CBaseMainParams : public CBaseChainParams
{
public:
CBaseMainParams()
{
nRPCPort =8332;
}
};
CBaseTestNetParams函数如下:
class CBaseTestNetParams : public CBaseChainParams
{
public:
CBaseTestNetParams()
{
nRPCPort =18332;
strDataDir ="testnet3";
}
};
CBaseRegTestParams函数如下:
class CBaseRegTestParams : public CBaseChainParams
{
public:
CBaseRegTestParams()
{
nRPCPort =18443;
strDataDir ="regtest";
}
};
可见,CBaseMainParams端口是8332,CBaseTestNetParams端口是18332,CBaseRegTestParams端口是18443.
注意:这里的私有链端口与板卡0.14不一样。0.14的版本是18332.
2) 设置globalChainParams网络参数(当前链的参数)
CreateChainParams的函数结构如下,与CreateBaseChainParams函数 流程是一样的,不在赘述
std::unique_ptr CreateChainParams(conststd::string& chain)
{
if (chain ==CBaseChainParams::MAIN)
returnstd::unique_ptr(new CMainParams());
else if (chain ==CBaseChainParams::TESTNET)
returnstd::unique_ptr(new CTestNetParams());
else if (chain ==CBaseChainParams::REGTEST)
returnstd::unique_ptr(new CRegTestParams());
throwstd::runtime_error(strprintf("%s: Unknown chain %s.", __func__,chain));
}
其实现与我们刚看到的BaseParams有点类似,只不过其少了Base单词而已,我们可以这样理解,在执行完链的基本参数设置后,比特币程序将设置相应链的主要参数了。从CreatChainParams函数实现我们可以看到,其实现与CreateBaseChainParams是一样的,都是根据链名称获取相应的链参数对象,只不过此处的链路参数类中包含的参数信息更详细些。主链、测试链以及私有链对应的类分别为CMainParams、CTestNetParams、CRegTestParamsstatic,这3个类的定义位于src/chainparams.cpp中,它们均继承了CChainParams类,通过CChainParams可知链参数类主要实现共识参数、CDNSSeedData种子数据、默认端口、创世块信息以及链交易数据等参数的设置。
我们已CMainParams为例,说明共识参数和创世块信息参数(这部分参考菜菜子同学的)
1)共识参数
标注consensus的都是共识参数
consensus.nSubsidyHalvingInterval = 210000; //区块奖励减半间隔
consensus.powLimit = uint256S("00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); //最小算力
consensus.BIP34Height = 227931; //BIP34协议在区块227931生效。
consensus.nPowTargetTimespan = 14 * 24 * 60* 60; // two weeks
consensus.nPowTargetSpacing = 10 * 60; //算力修改间隔,即10分钟
consensus.nMinerConfirmationWindow = 2016; // nPowTargetTimespan / nPowTargetSpacing
上面三个参数,联合看。
每14天改变一次挖矿难度,每10分钟出一个块,并修改一次算力,也即每2016个区块修改一次挖矿难度
2)创世块参数
genesis = CreateGenesisBlock(1231006505, 2083236893, 0x1d00ffff, 1, 50 * COIN); //第一个创世块奖励为50个比特币。
至此,程序根据用户输入的网络类型参数完成了比特币运行网络的设置。在这段代码中,我知道了私有网络,以前听得最多的是主网和测试网,而私有网或私有链基本很少听到,在这段代码中我知道了私有链是开发团队在开发时使用的网络,因为其挖矿难度很低,很容易进行程序的调试与功能试验。进而让我明白了一些区块链项目为什么会说在XX时刻要进入测试网阶段,然后再是最终的主网运行阶段。因此区块链开发过程应该是这样的:
今天终于看到比特币的基本配置参数了,从代码层理解了一些挖矿难度调整等信息。
/////////////////////////////////////////////////配置网络参数完毕分析完毕///////////////////////////////////////
区块链研习社比特币源码研读班 electroman
以下是广告:
我们区块链研习社已创建“区块链研习社币圈交流”小密圈”,在小密圈中,我们将带领大家一起学习区块链的原理与投资,还将提供区块链基本原理解答、交易所注册与交易操作、ICO交易与操作、投资分析、风险分析等内容。