美文网首页区块链研习社
比特币源码研读(9)-main函数

比特币源码研读(9)-main函数

作者: electroman | 来源:发表于2017-11-12 22:31 被阅读227次

    上文介绍了读取配置文件函数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交易与操作、投资分析、风险分析等内容。

    相关文章

      网友评论

        本文标题:比特币源码研读(9)-main函数

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