比特币源码研读10-程序入口函数解析(9)

最近加班到了新高度,晚上终于有点时间了,继续讲AppInitParameterInteraction 函数的 step3。

首先一条华丽丽的分割线,写着 Step 3: parameter-to-internal-flags,即用于内部标志的参数。

一. 内部标志参数

1. DEBUG 标志参数

首先判断对哪些目录进行调试日志的写入。

特殊情况: 假如 -debug=0 或者 设置了 -nodebug参数,那么关闭调试日志。

// ********************************************************* Step 3: parameter-to-internal-flags if (gArgs.IsArgSet("-debug")) { // Special-case: if -debug=0/-nodebug is set, turn off debugging messages const std::vector categories = gArgs.GetArgs("-debug");

        if (find(categories.begin(), categories.end(), std::string("0")) == categories.end()) {

            for (const auto& cat : categories) {

                uint32_t flag = 0;

                if (!GetLogCategory(&flag, &cat)) {

                    InitWarning(strprintf(_("Unsupported logging category %s=%s."), "-debug", cat));

                    continue;

                }

                logCategories |= flag;

            }

        }

    }

从函数GetLogCategory可以得知,所有目录都记录在 util.cpp文件的LogCategories数组,如下图,每个目录对应一个编号。

在init.cpp 中用到的 logCategories变量用来记录所有需要调试日志的集合,类型为uint32_t,

而上面目录中的编号每一个都对应32位中一位,所以每做一次“|”操作,就相当于把当前的编号加到logCategories集合中。

// Now remove the logging categories which were explicitly excluded

    for (const std::string& cat : gArgs.GetArgs("-debugexclude")) {

        uint32_t flag = 0;

        if (!GetLogCategory(&flag, &cat)) {

            InitWarning(strprintf(_("Unsupported logging category %s=%s."), "-debugexclude", cat));

            continue;

        }

        logCategories &= ~flag;

    }

上面这段代码则起到相反作用,即从集合中删除当前目录对应的编号,使用“&= ~”操作,“~"表示每一位取反,“&”表示与操作,与上反码就意味着去除当前目录编号。

2. DEBUGNET 标志参数

// Check for -debugnet

    if (GetBoolArg("-debugnet", false))

        InitWarning(_("Unsupported argument -debugnet ignored, use -debug=net."));

目前比特币网络暂不支持 -debugnet 参数,应该使用“-debug=net”代替。

3. SOCKS 标志参数

if (IsArgSet("-socks"))

        return InitError(_("Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported."));

目前程序也不支持 -socks 参数,假如设置了,那么程序将会提示初始化错误,并退出。

只能设置 SOCKS5才行,那么什么是SOCKS5 呢? 根据搜狗百科,SOCKS5 就是一种代理协议。

SOCKS5 是一个代理协议,它在使用 TCP/IP协议通讯的前端机器和服务器机器之间扮演一个中介角色,使得内部网中的前端机器变得能够访问Internet网中的服务器,或者使通讯更加安全。SOCKS5 服务器通过将前端发来的请求转发给真正的目标服务器, 模拟了一个前端的行为。在这里,前端和SOCKS5之间也是通过TCP/IP协议进行通讯,前端将原本要发送给真正服务器的请求发送给SOCKS5服务器,然后SOCKS5服务器将请求转发给真正的服务器。

SOCKS5服务器在将通讯请求发送给真正服务器的过程中,对于请求数据包本身不加任何改变。SOCKS5服务器接收到真正服务器的响应后,也原样转发给前端。 因此,SOCKS5协议是一种代理协议,对于各种基于TCP/IP的应用层协议 都能够适应,几乎是万能的。它虽然不能理解自己转发的数据的内部结构,但 是它能够忠实地转发通讯包,完成协议本来要完成的功能。

4. TOR 标志参数

if (GetBoolArg("-tor", false))

        return InitError(_("Unsupported argument -tor found, use -onion."));

目前程序也不支持 -tor参数,假如设置了,那么程序将会返回初始化错误。应该使用“-onion” 代替。另外关于tor(The Onion Router),之前已经有介绍,感兴趣的童鞋可以找前面的文章翻翻。这里不再赘述。

5. BENCHMARK 标志参数

if (GetBoolArg("-benchmark", false))

        InitWarning(_("Unsupported argument -benchmark ignored, use -debug=bench."));

使用 "-benchmark"提示该参数将被忽略,请使用 “-debug=bench” 代替。

6. whitelistalwaysrelay 标志参数

if (GetBoolArg("-whitelistalwaysrelay", false))

        InitWarning(_("Unsupported argument -whitelistalwaysrelay ignored, use -whitelistrelay and/or -whitelistforcerelay."));

使用 "-whitelistalwaysrelay"提示该参数将被忽略,请使用 “-whitelistrelay” 或者“whitelistforcerelay” 代替或者两者同时用之。

7. blockminsize标志参数

if (IsArgSet("-blockminsize"))

        InitWarning("Unsupported argument -blockminsize ignored.");

使用 "-whitelistalwaysrelay"提示该参数将被忽略,sorry,此参数并没有替代品,就此消失与茫茫代码中。

二. 内存池与区块索引检测参数

注释说,检查内存池和区块索引这两个参数在开发模式下默认设置为true。

// Checkmempool and checkblockindex default to true in regtest mode

int ratio = std::min(std::max(GetArg("-checkmempool", chainparams.DefaultConsistencyChecks() ? 1 : 0), 0), 1000000);

    if (ratio != 0) {

        mempool.setSanityCheck(1.0 / ratio);

    }

    fCheckBlockIndex = GetBoolArg("-checkblockindex", chainparams.DefaultConsistencyChecks());

    fCheckpointsEnabled = GetBoolArg("-checkpoints", DEFAULT_CHECKPOINTS_ENABLED);

根据帮助信息中的解释,

-checkmempool:表示每隔多少个交易进行一次sanity check。

-checkblockindex:每隔一段时间检查mapBlockIndex、setBlockIndexCandidates、chainActive和mapBlockUnlinked变量的一致性。

-checkpoints:该变量默认为true,表示需要验证校验点之前的区块信息是否正确;反之,如果为0,表示不需要检查,所有校验点的信息也都保存在chainparams中的checkpointdata中。

sanity check: 表示检查 内存池(mempool)中所有交易的一致性,即没有双花,所有输入都是合法的。

代码首先判断 chainparams中的 DefaultConsistencyChecks 是否为 true。如果为 false, ratio为 0,那么将不会做 sanity check.

关于chainparams,之前发表的文章中也介绍过,主要是根据不同的网络(main, testnet, regtest)为参数选择不同的值。

而对于DefaultConsistencyChecks,在main、testnet这两种模式下其返回值为false,详情可进入Chainparams.cpp文件的CMainParams与CTestNetParams类中便可以见之:fDefaultConsistencyChecks=false,regtest模式的返回值为true,同理可见于Chainparams.cpp的CRegTestParams类, 即只有在regtest网中才默认需要进行一致性检测。

另外, 函数std::min是取而二者中的最小值, ratio 的值取决于 -checkmempool参数值与1000000的最小者,很明显,前者将小于1000000。

tips: 关于checkpoints,即检查点,可以从以下链接了解到:

https://bitcoin.stackexchange.com/questions/1797/what-are-checkpoints

翻译过来大概是说,检查点是被硬编码进标准客户端的,而标准客户端会接受发生在该检查点之前的所有事务,而这些事务会被视为是有效地并且不可逆转的。假如有人尝试对在该检查点之前的区块进行硬分叉,那么该检查点不会接受该分叉。这将使得那些区块一成不变。由此可见,它的作用在于保护比特币网络免于51%攻击。


三、哈希假设有效参数

hashAssumeValid = uint256S(GetArg("-assumevalid", chainparams.GetConsensus().defaultAssumeValid.GetHex()));

    if (!hashAssumeValid.IsNull())

        LogPrintf("Assuming ancestors of block %s have valid signatures.\n", hashAssumeValid.GetHex());

    else

        LogPrintf("Validating signatures for all blocks.\n");

hashAssumeValid 参数默认值的获取过程有以下三个步骤

1. 获取链上共识参数

根据chainparams.GetConsensus()可溯源到 chainparams.h文件,其定义如下:

const Consensus::Params& GetConsensus() const { return consensus; }

Params 则是定义在 Params.h 中的结构体该结构体定义了影响链上共识的重要参数,相信大家看到这些参数的名字心情也会很鸡冻滴如下图所示,有 hashGenesisBlock(创世区块)、nSubsidyHalvingInterval (奖励减半时间间隔)、各种BIP启动高度及哈希值、powLimit、fPowAllowMinDifficultyBlocks(工作量证明参数)等等,大家有兴趣可以自行探索。

2. 获取默认假设有效参数值

上面结构体中当然也有我们所需要的 defaultAssumeValid 参数,其类型为 uint256,主要是用来存储256位二进制值。

3. 获取哈希值

第三步就是将获取到的值通过函数GetHex转换为十六进制

然后通过调用uint256S函数将变量转换为 uint256 对象。

/* uint256 from const char *.

* This is a separate function because the constructor uint256(const char*) can result

* in dangerously catching uint256(0).

*/

inline uint256 uint256S(const char *str)

{

    uint256 rv;

    rv.SetHex(str);

    return rv;

}

最后,判断假如hashAssumeValid不为空,则假定该区块所有的父区块都有有效的签名;反之,需要校验所有区块的签名,同时两种情况都要记录日志。


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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,198评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,663评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,985评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,673评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,994评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,399评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,717评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,407评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,112评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,371评论 2 241
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,891评论 1 256
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,255评论 2 250
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,881评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,010评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,764评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,412评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,299评论 2 260

推荐阅读更多精彩内容