四、区块链的技术原理—核心算法篇

上一篇已经详细介绍了区块的整个结构组成。

在这一篇中我们将结合区块中的信息介绍几点核心算法,同时也是整个区块链中核心中的核心,敲黑板,划重点。

这篇我们将会讲到:

  • 上一篇中提到的Merkle树是什么?Merkle树的树根 —Merkle Root 的算法。

  • 上一篇中提到的区块Hash值的算法。

  • 挖矿合法性算法验证。

1、Merkle Tree

1)Merkle Tree是一种树,大多数是二叉树,也可以多叉树,无论是几叉树,它都具有树结构的所有特点;

2)Merkle Tree的叶子节点的value是数据集合(区块体中的数据)的单元数据或者单元数据HASH。

3)非叶子节点的value是根据它下面所有的叶子节点值,然后按照Hash算法计算而得出的。

Merkle Tree可以看做前面所说Hash List的泛化,Hash List可以看作一种特殊的Merkle Tree,即树高为2的多叉Merkle Tree。

在最底层,和哈希列表一样,我们把数据分成小的数据块,有相应地哈希和它对应。但是往上走,注意,这里并不是和Hash List一样直接去运算根哈希,而是把相邻的两个数据哈希合并成一个字符串,然后将这个由两个Hash值拼成的字符串计算出新的Hash,,这样每两个哈希就结婚生子,得到了一个”子哈希“。如果最底层的哈希总数是单数,那到最后必然出现一个单身哈希,这种情况就直接对它进行哈希运算,所以也能得到它的子哈希。于是往上推,依然是一样的方式,可以得到数目更少的新一级哈希,最终必然形成一棵倒挂的树,到了树根的这个位置,这一代就剩下一个根哈希了,我们把它叫做 Merkle Root,而这就是所谓的Merkle Root的生成过程。

merkle树和merkle root:

9fdb5ff611af11e98608525400b4d70f.png

前面已经讲过,在p2p网络下载网络之前是如何通过Hash值来验证数据的完整性。

而Merkle Tree和Hash List的主要区别是,Merkle Tree可以直接下载并立即验证Merkle Tree的一个分支。因为可以将文件切分成小的数据块,这样如果有一块数据损坏,仅仅重新下载这个数据块就行了。如果文件非常大,那么Merkle tree和Hash list都很难做到,但是Merkle tree可以一次下载一个分支,然后立即验证这个分支,如果分支验证通过,就可以下载数据了。而Hash list只有下载整个hash list才能验证。(前面花了比较大的篇幅介绍了Hash算法,就是为了让大家提前了解,如何利用Hash去保证数据的一致性,这里的merkle root也是这个作用,只不过算法上有区别)

说了这么多, Hash Root也好、Merkle Root也罢,不管算法如何,剥开层层外壳,对于我们而言,它们的核心价值就是——验证确保数据的真伪性,我们常说区块链的数据不可篡改性也就是基于这一点。

2、区块Hash的生成

区块Hash是代表区块的唯一值,它有着一套固定的算法。

这里我们将采用验证法来还原Hash的生成。

以比特币区块277316为例(其信息来自网站http://blockchain.info)

企业微信截图_15615194036585.png

以上是区块高度为277316的区块的区块头的所有数据。

现在开始对区块277316的Hash值进行验证。

第一步,准备数据

1、版本号的十进制:2

2、merkle root+pre_hash的16进制:

0000000000000002a7bbd25a417c0374cc55261021e8a9ca74442b01284f0569
c91c008c26e50763e9f548bb8b2fc323735f73577effbc55502c51eb4cc7cf2e

3、2013-12-27 23:11:54 的时间戳:1388185914

4、难度目标(Bits)的十进制:419668748

5、随机数(nonce)的十进制:924591752

第二步,全部转换为16进制

1、00000002
2、0000000000000002a7bbd25a417c0374cc55261021e8a9ca74442b01284f0569
   c91c008c26e50763e9f548bb8b2fc323735f73577effbc55502c51eb4cc7cf2e
3、52be093a
4、1903a30c
5、371c2688

第三步,从big-endian转化为little-endian

先解释一下什么是endian?简单理解就是Big-endian是高字节在低地址,Litter-endian则高字节在高地址。

比如 ,int a = 0x05060708
在big-endian的情况下存放为:

字节号 0 1 2 3
数据 05 06 07 08

在little-endian的情况下存放为:

字节号 0 1 2 3
数据 08 07 06 05

发明人中本聪可能为了让机器计算更快,而变为了更接近机器的编码方式little-endian.

所以第二步的数据 我们通过从big-endian转化为little-endian,得到了:

1、02000000
2、69054f28012b4474caa9e821102655cc74037c415ad2bba70200000000000000
   2ecfc74ceb512c5055bcff7e57735f7323c32f8bbb48f5e96307e5268c001cc9
3、3a09be52
4、0ca30319
5、88261c37

第四步,拼接字符串,开始验证

1、我们将上面准备的字符数据重新拼接成一个新的字符串,这个字符串我们称之为
“block_header”:

02000000
+
69054f28012b4474caa9e821102655cc74037c415ad2bba702000000000000002ecfc74ceb512c5055bcff7e57735f7323c32f8bbb48f5e96307e5268c001cc9
+
3a09be52
+
0ca30319
+
88261c37

最终拼接得到的字符串block_header为:

0200000069054f28012b4474caa9e821102655cc74037c415ad2bba702000000000000002ecfc74ceb512c5055bcff7e57735f7323c32f8bbb48f5e96307e5268c001cc93a09be520ca3031988261c37

2、将上面的 block_header转成hex形式得到字节流:

b'\x02\x00\x00\x00i\x05O(\x01+Dt\xca\xa9\xe8!\x10&U\xcct\x03|AZ\xd2\xbb\xa7\x02\x00\x00\x00\x00\x00\x00\x00.\xcf\xc7L\xebQ,PU\xbc\xff~Ws_s#\xc3/\x8b\xbbH\xf5\xe9c\x07\xe5&\x8c\x00\x1c\xc9:\t\xbeR\x0c\xa3\x03\x19\x88&\x1c7'

3、对这个值进行两次SHA256运算,为什么要两次,这是因为SHA1在2017年被攻破,后面大家都觉得一次SHA256计算不安全。

两次SHA-256,即SHA256(SHA256(Hex(block_header))),最终得到字节流:

b'\xc4\xbd\xc7,\x1b\xb3\xa9D\xd9\xf2~\xb9(\xa9\xc4A\xdb\x96^\t;\xa1\xb9\xb6\x01\x00\x00\x00\x00\x00\x00\x00'

4、重新编码得到:

c4bdc72c1bb3a944d9f27eb928a9c441db965e093ba1b9b60100000000000000

看到后面有一堆0,感觉胜利的曙光快来了。其实这里实际上已经完成了,但是得到这个值是little-endian小端模式的,比特币区块上所记录的值也确实是这个值,但是我们在平常使用和网页浏览展示时,都是使用Big-endian大端顺序

所以这里我们再进行一次从little-endian转化为big-endian,就能得到:

0000000000000001b6b9a13b095e96db41c4a928b97ef2d944a9b31b2cc7bdc4

大功告成,看看http://blockchain.info所查询到的,完全一致,说明我们的方法是正确的,区块Hash的算法就是以我们前面的验算步骤一步步得来的。

企业微信截图_15615194036585.png

总的来说,算法不难,最难的地方就在于亲自验算的过程中,要把所有的隐藏知识都挖掘出来。中文资料中,极少有人做详细的通篇验算,而一旦真正理解了验算的过程,我们会发现比特币的算法真的不难。

附代码:

  //拼接block_header
    String header_hex = "02000000"
                  +
             "69054f28012b4474caa9e821102655cc74037c415ad2bba702000000000000002ecfc74ceb512c5055bcff7e57735f7323c32f8bbb48f5e96307e5268c001cc9"
                  +
            "3a09be52"
                  +
            "0ca30319"
                  +
            "88261c37";
       //字节串转成字节流
      String header_bin  = encode(header_hex.getBytes());
      System.out.println("HexUtil.encode Result : "+header_bin);

      // 双重hash
     String hash = applySha256(applySha256(header_bin));
     System.out.println("hash : "+hash);

     //字节流转成字符串
     decode(hash);
     System.out.println("hash : "+hash);

3,区块的合法性验证

如何确认区块的合法性,前面在介绍区块头时有提及过,简而言之就是区块Hash必须要小于Target Bits (目标难度值)。

这里我们继续采用验算法来验证过程。

区块Hash值在上一节已经得到验证,我们算出的是
第一步、准备数据

0000000000000001b6b9a13b095e96db41c4a928b97ef2d944a9b31b2cc7bdc4

Bits :419668748
最大目标:0x00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
区块Hash:0000000000000001b6b9a13b095e96db41c4a928b97ef2d944a9b31b2cc7bdc4

第二步、将Bits 转成 16进制得到

1903a30c

第三步、将1903a30c进行拆分,前2位我们称为幂者指数,后面6位称为系数,拆分后得到

19 和 03a30c

第四步、将拆分的值代入固定公式:

目标值=系数2^(8(幂者指数-3))次方

即:目标值 = 0x03a30c2^(8(0x19-3))

最终计算出来的就是真正意义上的目标值了。

0000000000000003a30c00000000000000000000000000000000000000000000

第五步、验算

target bits:

0000000000000003a30c00000000000000000000000000000000000000000000

max target:

0x00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF

计算结果target bits 小于难度目标 max target,符合要求,那这个结果就一定是网站上公布的数字了。

正确的hash值

在挖矿时,nonce随机数是未知的,要从0试到2^32,但是这个数字其实不大,只有4294967296次。以现在的一台矿机动辄14T每秒的算力,全部算完到上限也不需要一秒。所以需要使用创币交易中的附带信息,额外的字符串成为extra nonce,例如中本聪在比特币的创世区块中写道“The Times 03/Jan/2009 Chancellor on brink of second ballout for banks”(英国泰晤士报2009年1月3日文,财政大臣正处于实施第二轮银行紧急援助的边缘)嘲讽中心化的银行。

在2013年年底时,区块产生,这需要算力达到8T/s的设备,即每秒8*10^15次暴力验证,连续工作10分钟。这对于2018年的现在来说的确不算什么,一台矿机,不比两三块砖头大多少,就拥有14T/s的算力,只需要6,7分钟单独就可以挖到。但在当时,8T也是全网千分之一的算力了,需要当时最好的矿机上百台一起工作。而如果这个计算使用一台普通的桌面电脑,需要26年。如果使用一台iphoneX的话,每秒可以做70次计算,那么将需要四百万年。

通过上面的算法我们完整地回顾了比特币区块链的工作量证明算法,如果各位完全理清了其中的思路,也就可以手动实现自己的挖矿程序,或者另外尝试设计一些新的区块链产品了。最艰深的技术,我们希望能够在底层去了解,然而拨开云雾,其实底层的逻辑并不难。

不过比特币里面的技术远不止挖矿算法,加密算法,Script智能合约,各种协议,各种网络,交易的验证,每一个都充满了魔性,进出之间,不由得让人惊叹发明人知识的深度与广度。无论区块链是什么,将会怎样,但是以比特币为第一个大规模应用的区块链技术,已经扩散了开来,整个系统的严密与逻辑的复杂,的确让人着迷。

这一章内容是整个区块链的核心内容,多且杂,而且相对复杂,大家如果有什么疑问或者不理解地欢迎留言提问(前提是有人看)。

下一章:java简单实现区块链


其他工具

https://hash.online-convert.com/sha256-generatorSHA-256在线验证

https://webbtc.com/ 获取区块的json数据

http://blockexplorer.com/q/getdifficulty查询比特币的当前难度

http://bitcoin.sipa.be/查看难度的变化情况

http://blockexplorer.com/q/getblockcount查询比特币的区块数

https://bitcoin.org/en/developer-reference比特币区块链更详细的讲解(英文)

参考文章:

https://blog.csdn.net/wo541075754/article/details/54632929

https://www.jianshu.com/p/c6ef67755105

http://www.cnblogs.com/zhaoweiwei/p/difficulty.html

https://blog.csdn.net/jason_cuijiahui/article/details/79011118

https://blog.csdn.net/chaiyu2002/article/details/81237971

https://www.8btc.com/article/9688

你可能感兴趣的:(四、区块链的技术原理—核心算法篇)