You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

115 lines
10 KiB
Markdown

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 14 | PoW算法有办法黑比特币吗
你好,我是韩健。
谈起比特币,你应该再熟悉不过了,比特币是基于区块链实现的,而区块链运行在因特网上,这就存在有人试图作恶的情况。学完[01讲](https://time.geekbang.org/column/article/195662)和[13讲](https://time.geekbang.org/column/article/209450)之后有些同学可能已经发现了口信消息型拜占庭问题之解、PBFT算法虽然能防止坏人作恶但只能防止少数的坏人作恶也就是(n - 1) / 3个坏人 (其中n为节点数)。可如果区块链也只能防止一定比例的坏人作恶,那就麻烦了,因为坏人可以不断增加节点数,轻松突破(n - 1) / 3的限制。
那区块链是如何改进这个问题的呢答案就是PoW算法。
在我看来区块链通过工作量证明Proof of Work增加了坏人作恶的成本以此防止坏人作恶。比如如果坏人要发起51%攻击需要控制现网51%的算力成本是非常高昂的。为啥呢因为根据Cryptoslate 估算,对比特币进行 51% 算力攻击需要上百亿人民币!
那么为了帮你更好地理解和掌握PoW算法我会详细讲解它的原理和51%攻击的本质。希望让你在理解PoW算法的同时也了解PoW算法的局限。
首先我来说说PoW的原理换句话说就是PoW是如何运行的。
## 如何理解工作量证明?
什么是工作量证明(Proof Of Work简称PoW)呢你可以这么理解就是一份证明用来确认你做过一定量的工作。比如你的大学毕业证书就是一份工作量证明证明你通过4年的努力完成了相关课程的学习。
那么回到计算机世界,具体来说就是,客户端需要做一定难度的工作才能得出一个结果,验证方却很容易通过结果来检查出客户端是不是做了相应的工作。
比如小李来BAT面试说自己的编程能力很强那么他需要做一定难度的工作比如做个编程题。根据做题结果面试官可以判断他是否适合这个岗位。你看小李做个编程题面试官核验做题结果这就是一个现实版的工作量证明。
具体的工作量证明过程,就像下图中的样子:
![](https://static001.geekbang.org/resource/image/83/59/837a01a9d5adef33caa9eeea69143b59.jpg)
请求方做了一些运算,解决了某个问题,然后把运算结果发送给验证方,进行核验,验证方根据运算结果,就能判断请求方是否做了相关的工作。
需要你注意的是,这个算法具有不对称性,也就是说,工作对于请求方是有难度的,对于验证方则是比较简单的,易于验证的。
既然工作量证明是通过指定的结果来证明自己做过了一定量的工作。那么在区块链的PoW算法中需要做哪些工作呢答案是哈希运算。
区块链是通过执行哈希运算,然后通过运算后的结果值,证明自己做过了相关工作。为了帮你更好地理解哈希运算,在介绍哈希运算之前,咱们先来聊一聊哈希函数。
哈希函数Hash Function也叫散列函数。就是说你输入一个任意长度的字符串哈希函数会计算出一个长度相同的哈希值。假设我们对任意长度字符串比如"geektime"执行SHA256哈希运算就会得到一个32字节的哈希值就像下面的样子
```
$ echo -n "geektime" | sha256sum
bb2f0f297fe9d3b8669b6b4cec3bff99b9de596c46af2e4c4a504cfe1372dc52 -
```
那我们如何通过哈希函数进行哈希运算,从而证明工作量呢?为了帮你理解这部分内容,我举个具体的例子。
我们给出的工作量要求是,基于一个基本的字符串(比如"geektime"),你可以在这个字符串后面添加一个整数值,然后对变更后(添加整数值)的字符串进行SHA256哈希运算如果运算后得到的哈希值16进制形式是以"0000"开头的,就验证通过。为了达到这个工作量证明的目标,我们需要不停地递增整数值,一个一个试,对得到的新字符串进行 SHA256 哈希运算。
按照这个规则我们需要经过35024次计算才能找到恰好前4位为0的哈希值。
```
"geektime0" => 01f28c5df06ef0a575fd0e529be9a6f73b1290794762de014ec84182081e118e
"geektime1" => a2567c06fdb5775cb1e3ce17b72754cf146fcc6da75c8f1d87d7ab6a1b8c4523
...
"geektime35022" =>
8afc85049a9e92fe0b6c98b02b27c09fb869fbfe273d0ab84ad8c5ac17b8627e
"geektime35023" =>
0000ec5927ba10ea45a6822dcc205050ae74ae1ad2d9d41e978e1ec9762dc404
```
通过这个示例你可以看到,工作量证明是通过执行哈希运算,经过一段时间的计算后,得到符合条件的哈希值。也就是说,可以通过这个哈希值,来证明我们的工作量。
关于这个规则我也想多说几句这个规则不是固定的在实际场景中你可以根据场景特点制定不同的规则比如你可以试试分别运行多少次才能找到恰好前3位和前5位为0的哈希值。
现在,你对工作量证明的原理应该有一定的了解了,那么有同学肯定好奇了,在区块链中是如何实现工作量证明的呢?
## 区块链如何实现PoW算法的
区块链也是通过SHA256来执行哈希运算的通过计算出符合指定条件的哈希值来证明工作量的。因为在区块链中PoW算法是基于区块链中的区块信息进行哈希运算的所以我先带你回顾一下区块链的相关知识。
区块链的区块是由区块头、区块体2部分组成的就像下图中的样子。
* 区块头Block Head区块头主要由上一个区块的哈希值、区块体的哈希值、4字节的随机数nonce等组成的。
* 区块体Block Body区块包含的交易数据其中的第一笔交易是Coinbase交易这是一笔激励矿工的特殊交易。
![](https://static001.geekbang.org/resource/image/a0/1d/a0d4cfff95de26e64d85189dd47eee1d.jpg)
我想说的是拥有80字节固定长度的区块头就是用于区块链工作量证明的哈希运算中输入字符串而且通过双重SHA256哈希运算也就是对SHA256哈希运算的结果再执行一次哈希运算计算出的哈希值只有小于目标值target才是有效的否则哈希值是无效的必须重算。
学到这儿你可以看到在区块链中是通过对区块头执行SHA256哈希运算得到小于目标值的哈希值来证明自己的工作量的。
计算出符合条件的哈希值后,矿工就会把这个信息广播给集群中所有其他节点,其他节点验证通过后,会将这个区块加入到自己的区块链中,最终形成一串区块链,就像下图的样子:
![](https://static001.geekbang.org/resource/image/5a/9b/5afbe81873d69fc9dcd986d11c5c369b.jpg)
最后我想说的是算力越强系统大概率会越先计算出这个哈希值。这也就意味着如果坏人们掌握了51%的算力就可以发起51%攻击比如实现双花Double Spending也就是说同一份钱花2次。
具体说的话,就是攻击者掌握了较多的算力,能挖掘一条比原链更长的攻击链,并将攻击链向全网广播,这时呢,按照约定,节点将接受更长的链,也就是攻击链,丢弃原链。就像下图的样子:
![](https://static001.geekbang.org/resource/image/15/5a/15ae8837e42aaef0f8ee2e4227bf115a.jpg)
需要你注意的是即使攻击者只有30%的算力,他也有可能连续计算出多个区块的哈希值,挖掘出更长的攻击链,发动攻击; 另外即使攻击者拥有51%的算力,他也有可能半天无法计算出一个区块的哈希值,也就是攻击失败。也就是说,能否计算出符合条件的哈希值,有一定的概率性,但长久来看,攻击者攻击成功的概率等同于攻击者算力的权重。
## 内容小结
以上就是本节课的全部内容了本节课我主要带你了解了PoW算法的原理和51%攻击,我希望你明确这样几个重点。
1. 在比特币的区块链中PoW算法是通过SHA256进行哈希运算计算出符合指定条件的哈希值来证明工作量的。
2. 51%攻击,本质是因为比特币的区块链约定了“最长链胜出,其它节点在这条链基础上扩展”,攻击者可以通过优势算力实现对最长链的争夺。
3. 除了通过PoW算法增加坏人作恶的成本比特币还通过“挖矿得币”奖励好人最终保持了整个系统的运行稳定。
因为本讲是拜占庭容错算法的最后一讲我想多说几句学完了01讲的同学应该还记得我们提到Raft算法是非拜占庭容错算法。那么如果我们把Raft算法用于拜占庭场景中会怎么样呢
比如在比特币中我们采用了Raft算法实现共识而不是基于PoW算法的区块链那么就会出现这样的情况当恶意节点当选为领导者后他可以不断地告诉其他节点这些比特币都是我的按照Raft的约定其他节点也就只能接受这种情况谁让恶意节点是领导者呢**最终就会出现,所有的比特币都被恶意节点盗走的情况**,完全乱套了。
另外我想说的是因为拜占庭容错算法比如PoW算法、PBFT算法能容忍一定比例的作恶行为所以它在相对开放的场景中应用广泛比如公链、联盟链。非拜占庭容错算法比如Raft无法对作恶行为进行容错主要用于封闭、绝对可信的场景中比如私链、公司内网的DevOps环境。我希望你能准确理解2类算法之间的差异根据场景特点选择合适的算法保障业务高效、稳定的运行。
## 课堂思考
既然,我提了如何通过计算得到"0000"开头的哈希值来做实现工作量证明那么你不妨思考下如果约定是更多“0”开头的哈希值比如“00000000”工作量是增加了还是减少了为什么呢欢迎在留言区分享你的看法与我一同讨论。
最后,感谢你的阅读,如果这篇文章让你有所收获,也欢迎你将它分享给更多的朋友。