比特币源码分析之五:区块

2018-06-14 20:35:18 浏览数 (1)

比特币源码分析之五:区块

区块数据结构

区块的数据结构代码在block.cpp中

区块由区块头和交易集合组成,如下图

区块头由以下字段组成

int32_t nVersion; 表示版本号

uint256 hashPrevBlock; 表示前一个区块的hash值

uint256 hashMerkleRoot; 表示交易集合算出来的merkle 树的树根hash

uint32_t nTime; 表示区块的生成时间

uint32_t nBits; 表示当前区块需要的挖矿难度,可以简单理解为定义了挖矿需要hash的前几位是0

uint32_t nNonce; 一个用于挖矿的随机数

Txs是交易的集合

交易的主要结构已经在前面的文章中有介绍这里不再赘述,但是区块中有一个特殊的交易需要单独拿出来介绍一下,这个交易是每一个区块的第一个交易,被叫做coinbasetx

对比之前介绍的标准交易coinbasetx有几个不同

1、coinbasetx必须是在每一个区块的第一个交易

2、coinbasetx没有输入,只有输出,而这个输出一般是矿工的地址,而coinbasetx的输出其实就是给矿工的奖励。比特币体系中所有的比特币都是从这个途径出来了,然后流通在各个账户中。

3、coinbasetx的输入因为没有实际的交易意义,所以被用来存放别的信息,比如区块的witness merkle树的根hash,又比如区块的高度等,其中有一个字段和挖矿有关系,单独列出来,就是输入的脚本中会放一个nExtraNonce字段,这也是一个挖矿时候可以修改的随机数和blockheader中的nNonce字段结合可以达到调整block hash的目的

区块hash的计算方式

区块头中有一个字段hashPrevBlock这个字段表示的就是前一个区块的hash值,那么区块的hash值是怎么计算出来的呢?

其实很简单,区块的hash值就是区块头所有字段的hash256。那么细心的读者一定会注意到,如果区块的hash值只计算了区块头,那么交易集合怎么能保证不被恶意的第三方串改?

这个问题是区块头中有一个hashMerkleRoot,这个字段就是通过交易集合算出来的一个hash值,从网上盗图一张,放在这里供读者理解。

其中L1 L2 L3 L4就是一个一个的交易。

区块生成方式-挖矿

挖矿的主要代码在mining.cpp和miner.cpp中

先贴出来主逻辑

UniValue generateBlocks(…) 函数名称

{

While(…)主循环

{

nHeight = chainActive.Height(); 获取当前链的高度

生成一个区块数据结构,填上了当前的交易以及coinbasetx

pblocktemplate(BlockAssembler(Params()).CreateNewBlock(coinbaseScript->reserveScript));

CBlock *pblock = &pblocktemplate->block;

调整区块coinbasetx中的输入脚本中的nExtraNonce

IncrementExtraNonce(pblock, chainActive.Tip(), nExtraNonce);

不停的调整区块头中的nNonce来碰撞正确的hash

while(pblock->nNonce<nInnerLoopCount&&

!CheckProofOfWork(pblock->GetHash(), pblock->nBits, Params().GetConsensus()))

{

pblock->nNonce;

}

如果区块头中的nNonce的值用完了(加到最大值了),重启大循环,调整nExtraNonce

if (pblock->nNonce == nInnerLoopCount) {

continue;

}

尝试把挖矿出来的区块放入到候选链->主链->广播出去

ProcessNewBlock(Params(), shared_pblock, true, nullptr)

}

}

这段代码主要是完成以下步骤

1、生成一个区块的模版,填写一些基本的字段

2、调整coinbasetx的nExtraNonce

3、从0- nInnerLoopCount 累加区块头中的nNonce字段,如果累加到了nInnerLoopCount,转入第2步

4、计算区块头hash是否达标(也就是前n位是否为0),达标就进入第5步,否则重复3步

5、将生成好的区块经过验证等流程进入到候选链,进而进入主链,进而进入广播流程。

其中解释几个关键点

1、模版中的前n位为0,n是怎么确认的?

有一个公式,笔者也没有详细研究,原理就是比特币设想每10分钟生成一个区块,而每2016个区块会检查一下,这2016个区块生成的平均时间是否超过或者小于10分钟,如果超过10分钟就会把n调低,也就是降低挖矿难度,反之则把n调高。

另外一个疑问,如果某些恶意矿工,人为的把n设置低,来达到挖矿的目的会怎么样?岂不是它挖矿更容易?

这个问题也引出了比特币中伟大的发明,你把n降低了,再公网中广播的时候,区块的工作量就比别的矿主的少,也就导致了你的区块可能被别的矿工挖出来的区块pk掉的概率高,这就保证了矿工不敢随意降低n。(这么解释可能会比较难理解,后续文章会找机会进一步解释)

2、矿工的挖矿费是怎么确定的?

矿工的挖矿费是有两部分构成

1)、交易费,也就是所有交易的输出减去所有交易的输入的差价就是交易费Fee

2)、奖励,这个奖励是每4年减半,比如当前的奖励是25个比特币,再过一个四年周期会变成12.5个,依次类推。4年这个时间刻度是靠区块链的高度结合每一个区块10分钟的设想生成时间确定的。

0 人点赞