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

96
electroman
2017.11.26 15:21* 字数 2148

上次,我们分析了比特币的日志信息打印。今天我们继续分析下面的代码。

InitParameterInteraction();该函数位于init.cpp文件种。

从函数名字,我们可以初步了解,这是对输入参数的处理。

这里设计到的一些基本内容,这里监听的地址是其他节点的地址,监听方式如下

-bind,绑定监听地址,方式1

-whitebind,绑定监听地址,方式2

-connect,是否连接可信任节点

-proxy,代理模式,不需要监听(listen)

-listen,是否监听默认地址

-externalip,外部IP设置

-blocksonly,区块模式

-whitelistforcerelay,白名单模式

函数分析如下:

// whenspecifying an explicit binding address, you want to listen on it

// even when-connect or -proxy is specified

注释的意思是,当详细定义了一个地址以后,即使设置了-connect和proxy参数,程序也会监听这个地址(这一点,后文有详细说明)

1)绑定并监听地址

if (gArgs.IsArgSet("-bind")) {

     if(gArgs.SoftSetBoolArg("-listen", true))

     LogPrintf("%s: parameter interaction: -bind set -> setting-listen=1\n", __func__);

}

if(gArgs.IsArgSet("-whitebind")) {

   if(gArgs.SoftSetBoolArg("-listen", true)) 

    LogPrintf("%s: parameter interaction: -whitebind set -> setting-listen=1\n", __func__);

}

绑定地址的方式有两种,-blnd和-whitebind,软件对这两种参数的处理方式是一样的,如果绑定了地址,那么通过函数SoftSetBoolArg将listen设置为true

2)连接可信节点

if(gArgs.IsArgSet("-connect")) {

    // when onlyconnecting to trusted nodes, do not seed via DNS, or listen by default

    if(gArgs.SoftSetBoolArg("-dnsseed", false))

        LogPrintf("%s: parameter interaction: -connect set -> setting-dnsseed=0\n", __func__);

    if (gArgs.SoftSetBoolArg("-listen",false))

        LogPrintf("%s: parameter interaction: -connect set -> setting-listen=0\n", __func__);

}

判断gArgs中,是否包含-connect参数,如果包括,切没用绑定地址,则将-dnsseed与-listen设置为0,如果绑定了地址,则listen仍为1.这一点后续有详细说明。

3)代理模式

if(gArgs.IsArgSet("-proxy")) {

    // to protectprivacy, do not listen by default if a default proxy server is specified

    if(gArgs.SoftSetBoolArg("-listen", false))

        LogPrintf("%s: parameter interaction: -proxy set -> setting-listen=0\n", __func__);

    // to protect privacy, do not use UPNPwhen a proxy is set. The user may still specify -listen=1

    // to listenlocally, so don't rely on this happening through -listen below.

    if(gArgs.SoftSetBoolArg("-upnp", false))

        LogPrintf("%s:parameter interaction: -proxy set -> setting -upnp=0\n", __func__);

    // to protectprivacy, do not discover addresses by default

    if(gArgs.SoftSetBoolArg("-discover", false))

        LogPrintf("%s: parameter interaction: -proxy set -> setting-discover=0\n", __func__);

}

这是设置代理参数,目的是保护隐私,如果设置了设置了代理模式,-listen,upnp,以及discover均设置为false,即比特币后台进程只使用代理提供的监听地址与端口,并且不去查找默认的监听地址,这里upnp代表的意思是使用全局即插即用(upnp)映射监听端口,默认不使用。

4)监听设置处理

if(!gArgs.GetBoolArg("-listen", DEFAULT_LISTEN)) {

    // do not map ports or try to retrievepublic IP when not listening (pointless)

    if(gArgs.SoftSetBoolArg("-upnp", false))

        LogPrintf("%s: parameter interaction: -listen=0 -> setting-upnp=0\n", __func__);

    if(gArgs.SoftSetBoolArg("-discover", false))

        LogPrintf("%s: parameter interaction: -listen=0 -> setting-discover=0\n", __func__);

    if(gArgs.SoftSetBoolArg("-listenonion", false))

        LogPrintf("%s: parameter interaction: -listen=0 -> setting -listenonion=0\n",__func__);

}

监听处理,DEFAULT_LISTEN默认为true。如果监听设置为false,即不实施监听,则端口upnp,discover,listenonion均设置为false。Listenonion匿名地址监听,此处涉及通信机制的一个概念,第二代洋葱路由(onion routing),其解释如下:

Tor(The Onion Router)是第二代洋葱路由(onion routing)的一种实现,用户通过Tor可以在因特网上进行匿名交流。Tor专门防范流量过滤、嗅探分析,让用户免受其害。最初该项目由美国海军研究实验室赞助。2004年后期,Tor成为电子前哨基金会的一个项目。2005年后期,EFF不再赞助Tor项目,但他们继续维持Tor的官方网站。

5)外部IP处理

if(gArgs.IsArgSet("-externalip")) {

     // if anexplicit public IP is specified, do not try to find others

    if(gArgs.SoftSetBoolArg("-discover", false))

        LogPrintf("%s: parameter interaction: -externalip set -> setting-discover=0\n", __func__);

}

如果设置了外部的IP地址,那么bitcoind就不需要在找其他的监听地址了

6)区块模式参数处理

// disablewhitelistrelay in blocksonly mode

if (gArgs.GetBoolArg("-blocksonly",DEFAULT_BLOCKSONLY)) {

    if(gArgs.SoftSetBoolArg("-whitelistrelay", false))

        LogPrintf("%s: parameter interaction: -blocksonly=1 -> setting-whitelistrelay=0\n", __func__);

}

DEFAULT_BLOCKSONLY默认false,设置了区块模式以后,白名单参数whitelistrelay设置为false,即,区块模式下,白名单列表失效。

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

if (showDebug)

strUsage += HelpMessageOpt("-blocksonly", strprintf(_("Whetherto 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,否则将会互斥。

7)白名单节点参数处理

// Forcing relayfrom whitelisted hosts implies we will accept relays from them in the firstplace.

if(gArgs.GetBoolArg("-whitelistforcerelay",DEFAULT_WHITELISTFORCERELAY)) {

    if(gArgs.SoftSetBoolArg("-whitelistrelay", true))

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

    }

}

DEFAULT_WHITELISTFORCERELAY默认true,如果设置了whitelistforcerelay参数,则whitelistrelay为true,表示优先处理白名单节点。

下面分析,如果绑定了地址,即使设置了-connect和proxy参数,程序也会监听这个地址。

从代码分析来看,“表面上“设置了blind以后,listen=true,

if (gArgs.IsArgSet("-bind")) {

    if(gArgs.SoftSetBoolArg("-listen", true))

        LogPrintf("%s: parameter interaction: -bind set -> setting-listen=1\n", __func__);

}

但后面如果设置了connect,又会把listen设置为false

if(gArgs.IsArgSet("-connect")) {

    // when onlyconnecting to trusted nodes, do not seed via DNS, or listen by default

    if(gArgs.SoftSetBoolArg("-dnsseed", false))

        LogPrintf("%s: parameter interaction: -connect set -> setting-dnsseed=0\n", __func__);

    if (gArgs.SoftSetBoolArg("-listen",false))

        LogPrintf("%s: parameter interaction: -connect set -> setting-listen=0\n", __func__);

}

但实际情况是这样吗?

下面我们着重分析以下,这也是困惑我的地方。

假设没用blind,只是设置了connect。那么

Bind不执行,whitebind不执行,执行到if(gArgs.IsArgSet("-connect"))以后,执行if(gArgs.SoftSetBoolArg("-listen", false))

我们进入SoftSetBoolArg函数

bool ArgsManager::SoftSetBoolArg(conststd::string& strArg, bool fValue)

{

    if (fValue)

        return SoftSetArg(strArg, std::string("1"));

    else

        return SoftSetArg(strArg, std::string("0"));

}

strArg=listen,fValue=0,因此,会执行else语句,下面进入函数SoftSetArg:

bool ArgsManager::SoftSetArg(conststd::string& strArg, const std::string& strValue)

{

    LOCK(cs_args);

    if (IsArgSet(strArg)) return false;

        ForceSetArg(strArg, strValue);

    return true;

}

strArg=listen, strValue为0,函数判断是否有listen,如果有,则返回false,如果没有,则设置一个参数listen,并设置参数值为false,然后返回一个true。我们在此已经设置了listen,因此直接返回false。因此SoftSetBoolArg函数返回的也是false,listen设置为false

如果设置了bind,则listen=true,当执行-connet 语句中的if (gArgs.SoftSetBoolArg("-listen",

false))时, SoftSetBoolArg的传入函数是listen,和false,因此执行SoftSetArg(strArg,std::string("0"));

在SoftSetArg函数中,因为设置了listen,所以,运行代码if (IsArgSet(strArg)) return

false时,直接返回false,不会将listen设置为0,并且不会打印消息

之所以认为设置了-connect以后,就会把listen设置为false,是因为自己对SoftSetBoolArg函数理解不透。

至此,我们把函数InitParameterInteraction()分析完了。

区块链研习社比特币源码研读班  electroman

以下是广告:

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

比特币源码研读
Web note ad 1