区块链技术 blockchain区块链学习区块链研习社

比特币源码研读之六

2017-07-18  本文已影响1243人  菜菜子_forest

本文将继续参数处理其他部分源码的研读。

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

src/bitcond.cpp、src/util.h、src/util.cpp、src/init.h、src/init.cpp、src/chainparamsbase.h、src/chainparamsbase.cpp、src/chainparams.h、src/chainparams.cpp

一、比特币网络

比特币网络分为主网、测试网以及私有网三种网络,其中主网就是我们现在使用的正式运行的可进行实际交易的网络,在其上我们可以实现物品的交易与服务;测试网顾名思义即为公共测试网络,因为其实测试网,所以,其上的信息是可以重设的;私有网的难度很低,很容易产生块,所以开发者一般在私有网中开展应用的开发与自测试。三个网络的的英文名分别为:

主网:Main network

测试网:Testnet (v3)

私有网:Regression test

二、选择比特币网络

介绍完比特币网络的三种类型后,我们来看如下代码:

//Check for -testnet or -regtest parameter (Params() calls are only valid afterthis clause)

try{

SelectParams(ChainNameFromCommandLine());

} catch (const std::exception&e) {

fprintf(stderr,"Error: %s\n", e.what());

returnfalse;

}

首先我们来看代码注释,其注释的含义为检测-testnet或者-regtest参数。那么这两个参数是什么意思呢?它们分别是我们前面介绍的测试网和私有网。

知道了后面代码的具体功能后,我们就继续对代码进行深入剖析。注释后面的代码通过try catch异常捕捉机制实现比特币网络设置工作。在try代码块中,SelectParams函数以ChainNameFromCommandLine()返回值作为参数,SelectParams函数的声明位于src/chainparams.h中,其参数为字符串类型。那ChainNameFromCommandLine()的返回值是什么呢?

(1)获取网络名称

要知道ChainNameFromCommandLine()的返回值需进入src/chainparamsbase.cpp一看究竟。其函数实现如下:

std::string ChainNameFromCommandLine()

{

boolfRegTest = GetBoolArg("-regtest", false);

boolfTestNet = GetBoolArg("-testnet", false);

if(fTestNet && fRegTest)

throwstd::runtime_error("Invalid combination of -regtest and -testnet.");

if(fRegTest)

returnCBaseChainParams::REGTEST;

if(fTestNet)

returnCBaseChainParams::TESTNET;

returnCBaseChainParams::MAIN;

}

ChainNameFromCommandLine()函数从其名称可以看出,该函数将从命令行中获取链路的名称。其实现流程如图所示。

1)该函数首先获取"-regtest"与"-testnet"参数设置情况;

2)如果两个参数都设置了,因为一个比特币程序不可能同时存在两个网络,所以,程序将异常退出,同时抛出异常错误,由之前的try catch模块处理,打印异常错误提示信息;

3)如果只设置了回归测试,则返回CBaseChainParams::REGTEST,REGTEST为静态字符串常量,代表的是回归测试,与其并行的另两个网络描述字符串也为静态字符串常量,他们均在src/chainparamsbase.h中声明,也同时在src/chainparamsbase.cpp中定义。其声明与定义如下:

声明:

定义:

const std::string CBaseChainParams::MAIN = "main"; //主网

const std::string CBaseChainParams::TESTNET = "test"; //测试网

const std::string CBaseChainParams::REGTEST = "regtest"; //私有网

4)如果只设置了测试网络,,则返回CBaseChainParams::TESTNET;

5)如果都没有设置,则返回,则返回CBaseChainParams::MAIN。

(2)网络基本参数设置

在获得网络名称后,我们将其传给SelectParams函数,该函数的实现位于chainparams.cpp中,其函数实现如下:

void SelectParams(conststd::string& network)

{

SelectBaseParams(network);

pCurrentParams = &Params(network);

}

在该函数中首先调用SelectBaseParams函数,该函数的实现位于chainparamsbase.cpp中,其函数实现内容如下:

void SelectBaseParams(conststd::string& chain)

{

pCurrentBaseParams = &BaseParams(chain);

}

在该函数中,实现了对链参数对象pCurrentBaseParams的赋值,pCurrentBaseParams的类型为CBaseChainParams指针,其定义位于src/chainparams.cpp中,从定义可以看出pCurrentBaseParams为静态全局变量。

static CBaseChainParams* pCurrentBaseParams = 0;

CBaseChainParams类为前面提到的3种区块链基本参数的基类,3种区块链基本参数设置类分别为:CBaseMainParams、CBaseTestNetParams、CBaseRegTestParams,其定义位于src/chainparamsbase.cpp中,具体定义代码如下:

/**

*Main network主网

*/

class CBaseMainParams : publicCBaseChainParams

{

public:

CBaseMainParams()

{

nRPCPort = 8332;

}

};

static CBaseMainParams mainParams;

/**

*Testnet (v3)测试网

*/

class CBaseTestNetParams : publicCBaseChainParams

{

public:

CBaseTestNetParams()

{

nRPCPort = 18332;

strDataDir = "testnet3";

}

};

static CBaseTestNetParams testNetParams;

/*

*Regression test私有链

*/

class CBaseRegTestParams : publicCBaseChainParams

{

public:

CBaseRegTestParams()

{

nRPCPort = 18332;

strDataDir = "regtest";

}

};

static CBaseRegTestParams regTestParams;

从上述定义我们可以看到每个类的构造函数中定义了主链、测试链以及私有链使用的端口与数据目录,其端口分别为8332、18332以及18332。

在完成3种链的定义后,我们再来看BaseParams函数的实现就很容易明白其返回值的意义了:

CBaseChainParams& BaseParams(conststd::string& chain)

{

if (chain == CBaseChainParams::MAIN)

return mainParams;

else if (chain == CBaseChainParams::TESTNET)

return testNetParams;

else if (chain == CBaseChainParams::REGTEST)

return regTestParams;

else

throw std::runtime_error(strprintf("%s: Unknown chain %s.",__func__, chain));

}

BaseParams将返回对应链的基本参数对象,并赋值给pCurrentBaseParams。

3)主要参数设置

我们最后再来看SelectParams中的pCurrentParams = &Params(network);代码。其实现与我们刚看到的BaseParams有点类似,只不过其少了Base单词而已,我们可以这样理解,在执行完链的基本参数设置后,比特币程序将设置相应链的主要参数了。从Params函数实现我们可以看到,其实现与BaseParams是一样的,都是根据链名称获取相应的链参数对象,只不过此处的链路参数类中包含的参数信息更详细些。主链、测试链以及私有链对应的类分别为CMainParamsCTestNetParamsCRegTestParamsstatic,这3个类的定义位于src/chainparams.cpp中,它们均继承了CChainParams类,通过CChainParams可知链参数类主要实现共识参数、CDNSSeedData种子数据、默认端口、创世块信息以及链交易数据等参数的设置。

这里要着重讲解的是共识参数与创世块信息参数,它们分别为:

Consensus::Params consensus;

CBlock genesis;

因为我们主要使用主网,因此以主网中的参数内容来说明我们经常听到的区块奖励减半、出块时间、创世块奖励等参数是如何设置的。

区块奖励减半间隔:consensus.nSubsidyHalvingInterval = 210000;

算力极限值:consensus.powLimit =uint256S("00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff");

算力修改间隔:consensus.nPowTargetSpacing = 10 * 60;即10分钟

创世块genesis = CreateGenesisBlock(1231006505, 2083236893,0x1d00ffff, 1, 50 * COIN);第一个块的奖励为50个比特币

以上这些参数都是我们经常听到的名词,如果我们想创建自己命名的数字货币,只需简单修改这些参数即可,比如把区块奖励减半间隔修改为420000或其他数,创世块中比特币奖励的50该为100或其他数。所以要创建一个自己的数字货币并不难,关键在于看其是否有应用价值。

程序在每个类的定义之后,程序也定义了对应的静态链参数对象。

static CMainParamsmainParams;

staticCTestNetParams testNetParams;

staticCRegTestParams regTestParams;

Params将根据用户设置的链参数名称,将对应的链参数返回给pCurrentParams,从而完成链基本参数与主要参数的实现任务。

至此,程序根据用户输入的网络类型参数完成了比特币运行网络的设置。在这段代码中,我知道了私有网络,以前听得最多的是主网和测试网,而私有网或私有链基本很少听到,在这段代码中我知道了私有链是开发团队在开发时使用的网络,因为其挖矿难度很低,很容易进行程序的调试与功能试验。进而让我明白了一些区块链项目为什么会说在XX时刻要进入测试网阶段,然后再是最终的主网运行阶段。因此区块链开发过程应该是这样的:

以上就是本文的源码研读过程,通过源码的研读确实让我更好地理解区块链网络的运转过程,也让我清晰地明白市场上每个区块链的具体进程,这样可以让我更好地判断每个区块链产品的价值,对我投资区块链资产也有很大的帮助。

我是区块链研习社的菜菜子,我将继续深入研究比特币源码,源码研读系列也将继续更新,敬请期待!

作者:区块链研习社比特币源码研读班 菜菜子


以下是广告:

我们区块链研习社已创建“区块链研习社币圈交流”小密圈”,在小密圈中,我们将带领大家一起学习区块链的原理与投资,还将提供区块链基本原理解答、交易所注册与交易操作、ICO交易与操作、投资分析、风险分析等内容。

目前入圈价格初始定价50元,50人调整一次价格,每次调整幅度为50元!

上一篇下一篇

猜你喜欢

热点阅读