时间过得真快,转眼间比特币源码研读系列已经发表了7篇了,在这过程中,陆续不少朋友关注我的简书、向我打赏、喜欢我的文章,这些都是对我最好的鼓励与支持,也正是因为大家的支持我将继续开展源码研读工作,从技术上深入理解比特币与区块链!
本文将开始对InitParameterInteraction函数进行研读,通过其名称我们可以直观的理解该函数的功能是对传入参数的交互处理,也就是根据参数的信息做出相应的操作或执行相应的任务,这对于我们理解后续比特币程序运行的理解将会很关键,因为这些参数决定了其具体运行方式,所以,让我们一起认真地完成该函数的研读。
本文主要涉及的源码文件包括:
src/bitcond.cpp、src/util.h、src/util.cpp、src/init.h、src/init.cpp、src/net.h、src/torcontrol.h、src/torcontrol.cpp
InitParameterInteraction函数的运行主要分为以下7部分:
(1)绑定并监听地址
我们首先来看该部分的实现源码:
// when specifying an explicitbinding address, you want to listen on it
// even when -connect or -proxy isspecified
if (IsArgSet("-bind")) {
if (SoftSetBoolArg("-listen", true))
LogPrintf("%s:parameter interaction: -bind set -> setting -listen=1\n", __func__);
}
if (IsArgSet("-whitebind")) {
if (SoftSetBoolArg("-listen", true))
LogPrintf("%s: parameter interaction: -whitebind set -> setting-listen=1\n", __func__);
}
其注释的含义为:当显示指定了绑定地址后,即使指定了-connect和-proxy参数信息,程序将会接受来自外部的连接,并监听该地址。
绑定地址的方式有两种参数,分别是“-bind”和“-whitebind”,程序对这两种参数的处理方式是一致的,均通过SoftSetBoolArg函数实现“-listen”参数的设置,并将其值设置为true,表示要监听设置的外部连接IP地址。
这里要特别说明的是LogPrintf函数,因为该该函数在后续的代码中将会频繁出现,所以有必要对其进行说明。它在src/util.h中以预编译方式实现的定义,其本身不实现日志打印功能,而是通过调用LogPrintStr函数实现,该函数在src/util.cpp中进行了实现,其实现流程如图所示:
(2)连接可信节点
对连接可信节点参数的处理比较简单,其代码实现如下:
if (mapMultiArgs.count("-connect")&& mapMultiArgs.at("-connect").size() > 0) {
// whenonly connecting to trusted nodes, do not seed via DNS, or listen by default
if(SoftSetBoolArg("-dnsseed", false))
LogPrintf("%s: parameter interaction: -connect set -> setting-dnsseed=0\n", __func__);
if(SoftSetBoolArg("-listen", false))
LogPrintf("%s: parameter interaction: -connect set -> setting-listen=0\n", __func__);
}
其通过mapMultiArgs判断是否包含“-connect”参数,如果包括则将“-dnsseed(使用DNS查找节点)”和“-listen(即接受来自外部的连接,并对其进行监听)”设置为true。并进行日志打印,日志打印函数仍为LogPrintf。
这里需要注意的是,前面(1)中提到如果设置了”-bind”和”-whitebind”参数,程序将会监听指定的IP地址,即使指定了-connect和-proxy参数信息,程序将会接受来自外部的连接,并监听该地址。所以,此处代码的有效执行是在为设置”-bind”和”-whitebind”参数的情况下进行的。
(3)代理模式
设置代理参数的目的是为了保护隐私,所以此处将”-listen”、”-upnp”以及”-discover”均设置为false,也就是说比特币后台进程只使用代理提供的监听地址与端口,并且不去查找默认的监听地址。这里的upnp代表的意思是使用全局即插即用(UPNP)映射监听端口,默认不使用。
但与(2)中的说明一样,如果(1)中设置了”-bind”和”-whitebind”参数,程序将会监听指定的IP地址,即使指定了-connect和-proxy参数信息,程序将会接受来自外部的连接,并监听该地址。所以,此处代码的有效执行是在为设置”-bind”和”-whitebind”参数的情况下进行的。
(4)监听设置处理
监听设置处理代码在if (!GetBoolArg("-listen", DEFAULT_LISTEN)){}块中实现。
如果监听参数设置为false,即不实施监听则upnp(端口)、discover(自动发现默认地址)以及listenonion(匿名地址监听)均设置为false。
if (!GetBoolArg("-listen", DEFAULT_LISTEN))语句中的DEFAULT_LISTEN在src/net.h中定义。其定义默认为true,具体定义如下:
/** -listen default */
static const bool DEFAULT_LISTEN = true;
此处需要说明的是listenonion(匿名地址监听),此处设计一个通信机制的一个概念:第二代洋葱路由(onion routing),其解释如下:
Tor(The Onion Router)是第二代洋葱路由(onion routing)的一种实现,用户通过Tor可以在因特网上进行匿名交流。Tor专门防范流量过滤、嗅探分析,让用户免受其害。最初该项目由美国海军研究实验室赞助。2004年后期,Tor成为电子前哨基金会的一个项目。2005年后期,EFF不再赞助Tor项目,但他们继续维持Tor的官方网站。
比特币程序中使用src/torcontrol.h、src/torcontrol.cpp实现了Tor的控制,这个类的实现我们将在后续文章说明。
(5)外部IP参数处理
外部IP参数处理代码在if (IsArgSet("-externalip")) {}块中实现。
如果显示指定了公共IP地址,那么bitcoind就不需要查找其他监听地址了。
(6)区块模式参数设置
在区块模式参数设置代码在if (GetBoolArg("-blocksonly",DEFAULT_BLOCKSONLY)) { }块中实现。
DEFAULT_BLOCKSONLY在Src/net.h中定义,默认值为false,具体定义如下:
/** Default for blocks only*/
static const bool DEFAULT_BLOCKSONLY = false;
如果-blocksonly设置为false,那么在参数中将GetBoolArg设置为true,那么whitelistrelay参数将设置为false,意味着在区块模式下白名单列表将失效。
(7)强制白名单节点连接参数处理
强制白名单节点连接参数处理意味着比特币网络中的信息将优先在白名单节点间传递。
到此我们又完成了一个函数(InitParameterInteraction)源码的研读,在这个函数源码研读的过程中,我们梳理了bitcoind中日志打印的实现逻辑、时间戳显示方式以及输出途径(终端打印还是日志文件打印),还梳理了bitcoind对网络中IP地址的监听设置方法,知道了白名单列表,最后还知道了Tor(The Onion Router)。所以说,源码研读虽然比较晦涩、枯燥,但当我们看懂了其实现逻辑,学到了新知识,我们反而会觉得这是件很有意思的事情!
作者:区块链研习社比特币源码研读班 菜菜子
以下是广告:
我们区块链研习社已创建“区块链研习社币圈交流”小密圈”,在小密圈中,我们将带领大家一起学习区块链的原理与投资,还将提供区块链基本原理解答、交易所注册与交易操作、ICO交易与操作、投资分析、风险分析等内容。
目前入圈价格初始定价50元,50人调整一次价格,每次调整幅度为50元!
网友评论