前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >比特币源码分析之五:区块

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

原创
作者头像
qudamahcui
发布2018-06-14 20:35:18
1.2K0
发布2018-06-14 20:35:18
举报

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

区块数据结构

区块的数据结构代码在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分钟的设想生成时间确定的。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档