• 注册
    • 查看作者
    • 《重新创造比特币》第19章:工作量证明(下)

      0.前言

      本篇我们就来讨论上一篇引出的核心问题:设计出一个可以证明工作量的题目。

      1.寻找随机数

      很多时候,现实中冥思苦想的问题,在梦中确可以很轻松的得到答案。

      中本聪在梦境中尝到了好处,现在还不是醒来的时候。

      牛头人问:“什么样的题目可以证明节点付出的工作量呢?”

      小男孩说:“我想到的是:寻找随机数。这就好比去猜测一个人的生日,你只要趴在桌子上一直写呀写,总有一次可以猜中,只不过会花些体力,你付出的简单劳作就是工作量。”

      牛头人说:“我懂了,题目的本质就是不含任何逻辑的随机碰撞,随机碰撞最公平。”

      小男孩说:“对!我想到的工作量证明题目,猜的不是某人的生日,而是猜一个普通数字,这个数字添加到原来的消息后面,再对其求Hash,使得Hash值前面有很多个0。

      大家约定,想要拥有记账权,必须先要找到一个幸运数字,使得“区块消息+幸运数字”的Hash值以5个0开头。

      这里的“5”就代表难度,Hash前缀的0越多寻找的难度越大。”

      停顿了一下,小男孩觉得牛头人可能没有听明白,于是动手开始实际演示。

      因为区块消息比较长,我们用一句简短的消息来代替:"安心即乐土"。

      先对这句话求Hash,"安心即乐土"的Hash值为7511cedf823f0757d66c26769c8d15f8597e4384420e6cbebb0acbec5e73344a。

      我们看到,一般的Hash值都不会以0开头。

      接下来的任务,是找到一个幸运数字,使得‘安心即乐土+幸运数字‘的Hash值的前5位都是0,这个幸运数字就是我们要找的随机数。

      我们从0开始,将0添加到"安心即乐土"后面,变成:"安心即乐土0",求得Hash值:0b3844eec6204d01......

      因为,这个Hash值不以5个0开头,所以0不是符合规则的幸运数字。

      继续寻找,开始体力劳动:

      消息+幸运数字    Hash值前N位

      安心即乐土0    0b3844eec6204

      安心即乐土1    ebf1bbf0e1d2bc

      安心即乐土2    45963e7cbe226

      安心即乐土3    6b9e76dd1ca27

      安心即乐土4    ebf1bbf0e1d2bc

      安心即乐土5    6ec12dcfee54ffe

      安心即乐土6    53bde13314663

      安心即乐土7    d348d2eee3e8d

      安心即乐土8    276cfcd1386ffbd

      安心即乐土9    f78628f2b0e4e

      安心即乐土10    fe2e8cd0e0f3

      安心即乐土11    5cc0bc8d34f5fb

      安心即乐土12    764154ddd623

      安心即乐土13    e6c3bcb245fd

      安心即乐土14    7c18fb827e48

      安心即乐土15    283f7de03f01

      安心即乐土16    bce71436c4e

      安心即乐土17    4f76be60fb2b

      安心即乐土18    182530c711d1

      安心即乐土1e    6d5ec71c30c1

      安心即乐土20    b0161336bbbe

      安心即乐土21    d1f35d0522b3d

      安心即乐土22    e118e2ce041d

      安心即乐土23    052083fffd51d

       

       

      终于找到一个以0开头的,但是没有发现以5个0开头的,甚至没有以2个0开头的,继续寻找...

       

       

      安心即乐土520    e1f34d0t22b3

      安心即乐土521    g11ee2cg04sd

      安心即乐土523    0092e10ae10a

       

       

      终于在第523轮,发现了一个前缀是连续2个0的Hash值,继续寻找...

       

       

       

       

       

      一直找...

       

       

       

       

      百折不挠...

       

       

       

       

      过了很久很久,终于找到了!

       

       

      "安心即乐土832290344"的Hash值为:00000d4955bc5445e97...

      我们看到这个Hash值以5个0开头,所以,832290344就是我们要找的幸运数字。

      我们知道Hash值不可以倒推,所以只能随机碰撞,这8亿多次的随机碰撞,就是我的工作量证明。

      得到幸运数字之后,我就等于获得了记账权。接下来我就可以将这个区块消息广播出去,提供给其它节点同步。

      牛头人收到这条区块消息:"安心即乐土832290344"

      对其进行Hash计算,得出的Hash值满足我们的约定,即以5个0开头。

      牛头人就可以判定小男孩是付出了很大的工作量,付出了成本的人,大概率不会造假,所以将其同步到自己的账本中。

      同时,牛头人再将这条区块消息路由广播给其它邻居。

      其它节点也会像牛头人一样,进行验证和路由广播,小男孩的区块就会迅速被整个网络确认,成为最终账本中的一页。

      2.区块结构的改造

      小男孩继续补充到:“当然,‘安心即乐土832290344’只是在映射已经计算出随机数的区块消息,真实的区块结构会比较复杂,但是原理是一样的,因为寻找随机数的难度与区块消息的内容和长度无关。

      下面我们来看一下区块结构如何改造,可以承载工作量证明的新机制。

      我们可以将随机数放在区块的Header中,而不用一定是放在区块的尾部。

      另外Header中还需要加一个字段,来表示计算难度,例如5个0的Hash值前缀就表示难度值为5,9个0的Hash值前缀就表示难度值为9,难度值可以根据最近2100个区块的平均计算时间来进行动态调整,目的是让区块产生的间隔始终保持在10分钟左右。”(改造后的区块结构见下图)

      (备注:后续要将Difficulty改成nBits,现在为了保持简单性,简化了技术方案。另外,还应该引入Merkle树概念。)

      加入随机数和难度值字段的区块结构

      3.里程碑V0.1.0版本

      中本聪猛然醒过来,趁着记忆还算清晰,赶紧打开笔记本,按照小男孩的启发修改起代码来。

      中本聪专注的写了整整2天,Bitcoin系统升级好了,工作量证明方案替代了之前的临时方案(单点timestamp server)。

      所有节点更新至最新版本,重启运行,Bitcoin系统去掉了所有单点,第一次成为了真正意义上的群系统。

      从另一个视角,可以将Bitcoin系统看成是一个真正分布式的时间服务器(去中心化的timestamp server)

      因为这次系统升级实现了质的飞跃,所以中本聪将版本号定为了v0.1.0。

      我们来看看,v0.1.0版本的系统功能有哪些(见下图)

      v0.1.0版本的服务端功能

      服务端包括这么几个部分:
      1.网络连接:负责Bitcoin网络的自治。
      2.交易处理:负责Bitcoin系统的交易处理,属于系统的现在时。
      3.区块处理:负责Bitcoin系统的交易备份,属于系统的过去时。
      4.交易内存池:存储实时的交易数据。
      5.Block Chain:存储过去的交易数据。

      其中新添加的是区块处理部分:
      1.计算随机数:就是上面提到的工作量证明,获得随机数。
      2.生成区块:就是在记账,如果计算出了随机数,就可以将自己生成的区块广播出去,获得区块奖励。如果没有顺利计算出随机数,则放弃自己生成的区块,而选择同步网络中传递过来的区块。
      3.区块同步:同步其它节点的区块消息到自己的本地账本(Block Chain)。
      4.区块验证:通过一系列验证,来确保同步过来的区块是正确的。

      由于生成区块和计算随机数的目的是赚取区块奖励和交易手续费,其行为很像在地下随机的挖掘金矿,所以可以将这种行为称为挖矿,记账节点也就可以称之为矿工。(见下图)

      set in stone:一旦0.1版本发布,核心设计在其整个生命周期中都是一成不变的。

      4.竞争

      系统刚升级完,咖啡馆里的3台机器一下子变得嗡嗡作响。它们在争分夺秒的挖矿。

      每台矿机都想成为第一个找到那个随机数的幸运者。

      竞争是一轮接着一轮,每轮竞争大概的时间是10分钟。

      我们将视角聚焦到小男孩、牛头人和黄鼠狼之间的竞争。

      小男孩正在计算着自己的随机数,忽然邻居节点广播了一个新出炉的区块消息,小男孩一看,这个区块是三爷(节点3)生成的,心想三爷的机器性能不错啊,这一轮输给你了,我得赶紧把三爷的这个区块加入到自己的账本中,然后马上开始下一轮竞争。

      于此同时,牛头人和黄鼠狼也收到了三爷的新区块,处理过程和小男孩一样,也马上同步完区块,开始了下一轮的竞争。

      所以说,一个新的区块消息在网络中的广播,可以看成是一个以节点为中心的水波在网络的世界扩散,宣布着本轮的竞争结束,新的一轮开始啦!

      节点在广播区块消息

      区块构建

      新的一轮竞争开始了!

      小男孩首先要构建自己的区块数据,区块的交易数据来自于自己的内存池,选择几条交易数据放入本轮的区块之中是节点的自由,你可以选择几百条记录,也可以选择几万条记录。

      所以,每个矿工构建的区块中的交易记录都可能不同。

      当然,选择的交易记录越多,你会收获的手续费就越多,但是你的处理逻辑和广播速度就会变慢。

      这需要矿工根据自己的情况来进行平衡。

      甚至有的矿工追求极限的速度,构建的区块中不加入任何交易记录,只有一条区块奖励记录。这就是传说中的空区块。当然,这也算符合规则,可以被系统接受。

      小男孩根据自己的情况,按照交易费用由高到底的排序,从内存池中选择了前100条交易记录,将它们加入了新构建的区块的Transactions部分。

      然后将区块的Header部分的字段一一填写好,只剩下了随机数这个字段没有填写。

      接下来,小男孩开足马力,开始寻找那个唯一的随机数。

      与此同时,竞争者黄鼠狼和牛头人也在做着同样的挖矿行为。

      只不过黄鼠狼死心不改,还想再次将区块奖励的数字又50改为500。

      黄鼠狼为了追求区块的构建和传播速度的极限,竟然构建了一个空区块,区块的Transations中只有一条区块奖励的交易记录,奖励的数字是500Bitcoin。

      然后同样开始开足马力的计算随机数。

      黄鼠狼曾经想过,能不能在上一轮区块广播之前就提前开始计算随机数,后来发现不行,因为新的一轮的区块中要在Header中填写上一轮区块的Hash值,所以必须得等到上一轮的区块消息传递到自己手里,才能开始。

      区块广播

      小男孩,牛头人和黄鼠狼就像是在同一条跑道上赛跑。先发出区块广播者就是冠军。

      经过了10分钟左右的激烈竞争,黄鼠狼在10分11秒第一个找到了随机数,小男孩稍微慢了一点在10分13秒找到了随机数,牛头人最慢在10分14秒找到了随机数。

      黄鼠狼开心坏了,急忙将找到的随机数填写到区块中,并将区块消息广播了出去。

      小男孩和牛头人也同样将自己的区块消息广播到网络中。

      接下来就看网络中的其它节点来投票了。因为它们三个广播的时间几乎是同时发出,所以还可以彼此竞争一下,这就好像水面上同时有3个水波在扩散。(见下图)

      三个节点三个水波

      区块验证

      因为Bitcoin的点对点网络的特性很像水面,所以大概率,最先发出的水波会最先传遍整个水面。

      果然,黄鼠狼的区块消息被其它节点首先收到,但是大家不会盲目的将这个区块加入到自己的账本中。

      而是首先要进行区块验证:区块的语法是否正确,区块中的交易是否合法。

      当大家验证发现黄鼠狼的区块奖励不符合约定,大家都皱起眉头,果断将黄鼠狼的区块消息放弃。

      紧接着大家又收到了小男孩和牛头人的区块消息。因为小男孩发起广播的时间比牛头人快了1秒,所以整个网络中,大多数的节点都是先收到了小男孩的区块消息。

      大家同样对小男孩的区块进行验证,发现没有问题,就马上将其同步到自己的账本中。然后马上进入下一轮的挖矿竞争中。

      网络的弹性

      这时候你会问,还有一小部分节点,由于离牛头人的距离更近,先接受到了牛头人的区块消息,那么如果它们也以先收到的区块为准,进行同步,那岂不是选错了区块。

      其实不会,节点在收到牛头人的区块消息之后,不会马上认同,而会看看身边的邻居是否也同样在广播牛头人的区块消息,如果发现身边的邻居广播的区块消息和自己一样,则可以认同牛头人的区块是最先发出。如果发现身边的邻居广播的区块不同,有的邻居广播的竟然是小男孩的区块消息,节点就会怀疑自己收到的牛头人的区块没准不是最先发出。这时候就要统计一下邻居的广播,发现10个邻居中有7个人都在向外广播小男孩的区块消息,只有3个人在广播牛头人的区块消息,所以就得出结论,小男孩才是正确的选择。

      当然,也会存在特殊情况,如果身边的邻居也错了,那么这一小部分节点就会错误的选择了将牛头人的区块同步到了自己的账本中。这种时候系统中就存在两套账本,这就是暂时性的区块链的分叉。(见下图)

      分叉

      关于分叉的问题我们下一篇在来详细讨论。

      竞争守护正义

      我们回过头再来看看可怜的黄鼠狼,由于自己的区块被大多数节点的放弃,自己感觉赔了一个亿。

      自己付出那么多劳动成本,全都作废了。

      黄鼠狼在思考,要不以后就好好做人,不再偷鸡摸狗了,就正常挖矿赚Bitcoin得了。

      经过这次教训,黄鼠狼老实了一点。

      投票

      讲过上面一轮的竞争,我们可以看出,节点选择同步哪个区块,就等于在给自己认同的区块投票。

      投给自己认为正确,并且最早的区块。

      基于竞争机制的民主投票才可能朝着正确的方向前行。

      5.后记

      Bitcoin本身是车轮,全球账本(Metanet)才是车,比特币是这个全球账本上的通用货币,其目的是提供这辆车的燃料,维护这个不可篡改账本的安全以及提供经济激励。在有了使用价值之后,才延伸出“通用货币”,或者说“钱”的属性。只是在造车的时候,需要先造轮子,再有了轮子之后,才上车架。

      下一篇我们将讨论分叉的概念。

      参考:

      公众号:汤强《鸡一嘴鸭一嘴,应该听谁?》- https://mp.weixin.qq.com/s/DgKUftTAgdpKnox6ZpLq8Q

    • 0
    • 0
    • 0
    • 85
    • 单栏布局 侧栏位置: