比特币共识

去中心化共识

没有中心机构验证,网络中的节点依据简单的规则各自干着自己的事情:收集交易,证明工作量,确认交易,获得奖励,维护着总账,这一切能够圆满运行依赖于去中心化的自发共识机制。

比特币的去中心化共识由所有网络节点的4种独立过程相互作用而产生:
▷ 每个全节点依据综合标准对每个交易进行独立验证
▷ 通过完成工作量证明算法的验算,挖矿节点将交易记录独立打包进新区块,
▷ 每个节点独立的对新区块进行校验并组装进区块链
▷ 每个节点对区块链进行独立选择,在工作量证明机制下选择累计工作量最大的区块链

《比特币共识》 比特币挖矿达成共识的过程

交易的独立校验

每一笔交易被最近的节点收集后,首先进行的是验证这笔交易的有效性。验证的目的是清除无效的交易,留下有效的交易。
验证的项目比较多,比如:语法和数据结构是否正确;输入与输出列表都不能为空;输出值和总量在有效范围内;不是挖矿类型的收入(创币交易或者coinbase交易无需验证);解锁脚本(scriptSig)和锁定脚本(scriptPubkey)必须要符合格式要求;交易费用不得过低导致无法确认等等。

挖矿节点整合交易到候选区块

挖矿节点不必一定是全节点。它们对新区块特别敏感,因为新区块产生就意味着一次工作量证明的结束,和一次新的工作量证明的开始。与其他非挖矿节点不同的是,挖矿节点的目的是构建候选区块(新区块)
挖矿节点整合临近的非挖矿节点的交易池和自己的交易池,然后将交易与区块链中的新区块进行比对,剔除被刚刚产生的新区块收录的交易,将这些交易放入候选区块。候选区块是未包含工作量证明验证的区块。

将交易分配优先级

交易的优先级是由交易花费的UTXO的“块龄”决定。

交易的优先级是通过输入值和输入的“块龄”乘积之和除以交易的总长度得到的:
Priority = Sum (Value of input * Input Age) / Transaction Size
UTXO的“块龄”是自该UTXO被记录到区块链为止所经历过的区块数,即这个UTXO在区块链中的深度。交易记录的大小由字节来表示。

从公式上看,交易输入值高、“块龄”大的交易比那些新的、输入值小的交易拥有更高的优先级。还有一种情况是高优先级交易即便是零矿工费,也可以优先被处理。当区块大小上限为MAX_BLOCK_SIZE没达上线时,矿工会优先选择矿工费高的交易来填充剩下的区块。

在区块被填满后,内存池中的剩余交易会成为下一个区块的候选交易。因为这些交易还留在内存池中,所以随着新的区块被加到链上,这些交易输入时所引用UTXO的深度(即交易“块龄”)也会随着变大。由于交易的优先值取决于它交易输入的“块龄”,所以这个交易的优先值也就随之增长了。最后,一个零矿工费交易的优先值就有可能会满足高优先级的门槛,被免费地打包进区块。

由于网络等各种原因未被确认验证加入候选区块的交易,也是有可能出现交易失败的,这种情况就需要重新发起交易,重新支付交易费。

创币交易

每个区块中的第一笔交易都是一笔特殊的交易,叫创币交易,或者coinbase交易。这笔交易的内容是向该区块的矿工地址发放挖苦你奖励。

与常规交易不同,创币交易没有输入,不消耗UTXO。它只包含一个被称作coinbase的输入,仅仅用来创建新的比特币。创币交易有一个输出,支付到这个矿工的比特币地址。

矿工费

计算矿工费的总额,将已添加到区块交易的输入和输出分别进行加总,然后用输入总额减去输出总额得到矿工费总额,公式如下:
Total Fees = Sum(Inputs) – Sum(Outputs)

创币交易的结构

《比特币共识》 创币交易输入的结构

创币交易不包含“解锁脚本“(又称作 scriptSig)字段,这个字段被coinbase数据替代,长度最小2字节,最大100字节。除了开始的几个字节外,矿工可以任意使用coinbase的其他部分,随意填充任何数据。

构造区块头

《比特币共识》 区块头的结构

前区块哈希是区块链中前一个区块(父区块)的哈希值。创币交易作为区块中的首个交易,后将余下的交易添至其后。
默克树根是这些交易的哈希值逐层地、成对地组合,直到最终组合并成一个根节点。merkle数的根节点将全部交易数据摘要为一个32字节长度的值。
一个4字节的时间戳,以Unix纪元时间编码,即自1970年1月1日0点到当下总共流逝的秒数。
难度目标值,为了使得该区块有效,这个字段定义了所需满足的工作量证明的难度。难度在区块中以“尾数-指数”的格式,编码并存储,这种格式称作“难度位”。这种编码的首字节表示指数,后面的3字节表示尾数(系数)。
nonce,初始值为0。Nonce是用来改变加密函数输出的,类似这样在语句末尾的变化的数字叫做nonce(比如我是一只小鸟1,我是一只小鸟2,我是一只小鸟3,这当中的数字)。意思就是通过这个值的改变造成输入值的差异。

区块头完成全部的字段填充后,挖矿就可以开始进行了。挖矿的目标是找到一个使区块头哈希值小于难度目标的nonce。挖矿节点通常需要尝试数十亿甚至数万亿个不同的nonce取值,直到找到一个满足条件的nonce值。

构建区块

挖矿就是预先给你一个数值作为目标值,你使用矿机随机寻找数值,哈希以后看是否小于目标值,小于就算成功,如果不满足,则修改Nonce参数,再次进行哈希,直到得到一个值作为区块头哈希值,满足小于设定值。哈希输入值和区块头哈希值结果是一一对应的,绝对不会重复。

哈希函数的结果无法提前得知,也没有能得到一个特定哈希值的模式。哈希函数的这个特性意味着:得到哈希值的唯一方法是不断的尝试,每次随机修改输入,直到出现适当的哈希值。

工作量证明算法

这样进行计算的方式就是说找到作为哈希源头的值非常困难,但是验证是否正确非常容易。也就符合工作量证明设计的要求。
无论输入的大小是多少,SHA256函数的输出的长度总是256bit。
工作量证明举例:
最简单的例子,找到一个语句,使之哈希值的十六进制表示以0开头。从概率结算,用16次输入就可以得到(16进制)。如果增加16进制哈希值的精度(比如精确到更多位数),那么难度就会迅速大幅提升。
例如掷骰子,如果设定的目标是两个骰子之和小于12,那么基本上只要不是两个6,应该比较容易。下一局设定为11,只要不是两个6,和1个5,一个6,也不太难。如果设定为5,甚至是3,需要投掷的次数就会大大增加,也就是需要更多的工作量。

矿工用一些交易构建一个候选区块。接下来,这个矿工计算这个区块头信息的哈希值,看其是否小于当前目标值。如果这个哈希值不小于目标值,矿工就会修改这个nonce(通常将之加1)然后再试一次。按当前比特币系统的难度,矿工得试10^15次(10的15次方)才能找到一个合适的nonce使区块头信息哈希值足够小。
随着难度位一位一位地增加,查找正确结果的时间会呈指数级增长。如果你考虑整个256bit数字空间,每次要求多一个0,你就把哈希查找空间缩减了一半。因而找到正确的哈希值更加困难。

难度表示

在区块中看到难度目标,其被标为”难度位”或简称”bits”。这个标记的值被存为系数/指数格式,前两位十六进制数字为幂,接下来得六位为系数。比如在区块277,316中,它的值为 0x1903a30c。0x19为幂,而0x03a30c为系数。
计算难度目标的公式为:
target = coefficient * 2^(8 * (exponent – 3))
由此公式及难度位的值 0x1903a30c,可得:
target = 0x03a30c * 2^(0x08 * (0x19 – 0x03))
难度设定的目的就是为了无论挖矿能力如何,新区块产生速率都保持在10分钟一个。不允许太快,不允许太慢。

在一个完全去中心化的网络中,这样的调整是如何做到的呢?难度的调整是在每个完整节点中独立自动发生的。每2,016个区块中的所有节点都会调整难度。难度的调整公式是由最新2,016个区块的花费时长与20,160分钟(两周,即这些区块以10分钟一个速率所期望花费的时长)比较得出的。难度是根据实际时长与期望时长的比值进行相应调整的(或变难或变易)。简单来说,如果网络发现区块产生速率比10分钟要快时会增加难度。如果发现比10分钟慢时则降低难度。
值得注意的是目标难度与交易的数量和金额无关。这意味着哈希算力的强弱,即让比特币更安全的电力投入量,与交易的数量完全无关。

成功构建区块

挖矿节点(最可能是矿池中的一个节点)在对区块以每秒亿万次的速度进行nonce测试,得出一个解,当把这个结果放进区块头时,nonce 验证后就会产生一个区块哈希值,这个值小于难度目标值,这就说明这个区块挖矿成功了。该节点将消息传到相邻节点,临近节点验证后继续传播这个区块,更多的节点收到验证,他们立即停止对这个区块相同高度区块的计算,并立即开始计算区块链中下一个区块的工作。

校验新区块

产生的新区块会被网络中的节点进行独立校验,独立校验是各个节点自己的独立行为,主要为了防止错误,奖励诚实者。
校验的内容有:
▷区块的数据结构语法上有效
▷ 区块头的哈希值小于目标难度(确认包含足够的工作量证明)
▷ 区块时间戳早于验证时刻未来两个小时(允许时间错误)
▷ 区块大小在长度限制之内
▷ 第一个交易(且只有第一个)是coinbase交易
▷ 使用检查清单验证区块内的交易并确保它们的有效性

矿工们必须构建一个完美的区块,基于所有节点共享的规则,并且根据正确工作量证明的解决方案进行挖矿,他们要花费大量的电力挖矿才能做到这一点。如果他们作弊,所有的电力和努力都会浪费。这就是为什么独立校验是去中心化共识的重要组成部分。

区块链的组装与选择

一旦一个节点验证了一个新的区块,它将尝试将新的区块连接到到现存的区块链,将它们组装起来。
一个节点维护着三种区块:
第一种是连接到主链上的
第二种是从主链上产生分支的(备用链)
最后一种是在已知链中没有找到已知父区块的

主链上的区块

主链都是累计了最多难度的区块链。大多数情况主链也包括了最多的区块。当节点接收到新区块,准备加入到区块链中时,节点会看一下这个区块的“previous block hash”字段,这个字段是该区块对其父区块的引用。新的节点将尝试在已存在的区块链中找出这个父区块。大多数情况下,父区块是主块链的“顶点”,这就意味着这个新的区块延长了主链。
有时候主链也会有分支,这些分支中的区块与主链上的区块互为“兄弟”区块。这些区块是有效的,但不是主链的一部分。 保留这些分支的目的是如果在未来的某个时刻它们中的一个延长了并在难度值上超过了主链,那么后续的区块就会引用它们。

备用链

节点也会将新区块延续到不是主链的备用链,同时比较备用链与主链的难度。如果备用链比主链积累了更多的难度,节点将收敛于备用链,意味着节点将选择备用链作为其新的主链,而之前那个老的主链则成为了备用链。如果节点是一个矿工,它将开始构造新的区块,来延长这个更新更长的区块链。这就是发生了分叉。

找不到父区块的孤区块

节点验证了一个区块,但是找不到其父区块,这种情况的发生是由于网络在接近的时间里被挖出来,节点有可能会以相反的顺序接收到它们。这些孤块会被放在孤块池,一旦后续找到其父区块,将会迅速脱皮孤块池,链接到父区块,进入区块链中。

区块链分叉

去中心化的网络,区块产生验证会有时间差异,会发生后产生的区块先被网络节点验证并准备进入区块链,但是却找不到父区块。与孤块不同的是,这些还有可能是多个区块组成的链。

解决的办法是,每一个节点总是选择并尝试延长代表累计了最大工作量证明的区块链,也就是最长的或最大累计难度的链。节点通过将记录在每个区块中的难度加总起来,得到建立这个链所要付出的工作量证明的总量。只要所有的节点选择最长累计难度的区块链,整个比特币网络最终会收敛到一致的状态。分叉即在不同区块链间发生的临时差异,当更多的区块添加到了某个分叉中,这个问题便会迎刃而解。

分叉的发生

两个区块在网络跳数较远的环境下几乎被同时发现,而且两个区块中还可能包含相同的交易。它们分别被临近的节点验证,被标记为同样父区块加入区块链。这些节点又分别开始了自己的候选区块的工作量证明计算。如下图中的红色区块和绿色区块。

《比特币共识》 分叉的发生

网络的分裂

比特币网络上的节点对于区块链的顶点产生了分歧,一派以红色区块为顶点,而另一派以绿色区块为顶点。两个顶点以各自顶点开始延续自己的候选区块,生成新区块并逐渐形成自己的区块链。

《比特币共识》 网络分裂

重新共识

新区块产生,节点就会将区块附加到两个区块链中的一个上,比如备用链,备用链增加的区块会进行同步,其他节点在主链上找不到父区块,就会导致节点必须选择备用链,备用链成为更长链,这些节点接纳了新的更长的链,被迫改变了原有对区块链的观点,这就叫做链的重新共识。节点对原来主链追加的候选区块就成为孤块,重新选择父区块。

《比特币共识》 形象化的区块链分叉事件:全网在最长链上重新共识

参考内容:

《精通比特币》

    原文作者:乔延宏
    原文地址: https://www.jianshu.com/p/d68bb74299fe
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞