《比特币是什么?(中)》介绍了挖矿奖励和共识算法。矿工可以通过记账获得区块奖励,而共识机制确保了大家始终在同一条主链上前进。
比特币使用工作量证明作为共识机制,矿工用算力来争取记账权,从而获得奖励。这篇文章将继续探讨工作量证明的原理。
密码散列函数 🔗
如果你经常在网络上下载文件,特别是用 BT 这样的 P2P 下载方式,那么你可能会留意到相当一部分网站提供了文件的 MD5 / SHA-1 / SHA-256。
![](windows-sha256.png)
上图表格中的 64 位十六进制数就是 Windows 10 光盘映像文件的 SHA-256(64 位十六进制数可以表示成 256 位二进制数),比如「简体中文 64-bit」版本的 SHA-256 是 3377C16D09BDA29A6B6CD6EE9D73B859056796B0DDE4226671953138449EC5E1。
由于$16^1=2^4$,每 1 位十六进制数都可以表示为 4 位二进制数。同理,如果将 64 位十六进制数表示成二进制,会变成 256 位,这也是 SHA-256 名字中 256 的由来。
虽然计算机使用的是二进制,但是写给人看的时候,我们通常用读写起来更高效的 2 的次幂进制(如八进制、十六进制)表示。例如,同样表示两个字节,写成二进制是 11000010 00100111,写成十六进制则是 C2 27。
这串十六进制数有什么用?简单来说,这是 Windows 10 光盘映像文件的指纹(fingerprint)。假如你花了一个小时下载 Windows 10,又花了十分钟把它做成 U 盘启动盘,到安装的时候才发现有文件损坏了,这就很难受了。
密码散列函数(CHF, cryptographic hash function)可以为任意长度的消息生成固定长度的指纹,或者叫摘要(digest),所以密码散列函数也叫消息摘要函数。这样一来,我们可以用同样的算法对下载的文件生成摘要,并且跟网站上提供的进行对比,来确保我们下载的文件是正确、完整的。
密码散列函数把任意长度的消息变成固定长度的摘要,显然是不可逆的,而且存在不同消息对应同一个摘要,即满足 $m_1 \neq m_2$,但 $hash(m_1)=hash(m_2)$,这种情况被称为碰撞(collision)。一个好的密码散列函数需要是抗碰撞的,也就是说,很难找出两个具有相同摘要的不同消息。
工作量证明 🔗
对任意消息做 SHA-256 都能生成一个 $[0, 2^{256}-1]$ 之间的数字(因为是 256 位的二进制数),每个数字的概率均等。已知 $m$ 计算 $SHA256(m)$ 很容易,但反过来,已知 $SHA256(m)$,找到符合条件的 $m$ 非常困难。比特币的工作量证明正是利用密码散列函数的这种特性来设计的。
![](sha256.png)
你可以在编程加的 Playground 中,用 Python 计算 SHA-256,会发现即便只差了一个字符,SHA-256 的结果大相径庭。这种现象在密码学中也被称为雪崩效应(avalanche effect),是一种密码散列函数的理想属性。
比特币每个区块头部有很多信息,像是上一个区块头部的摘要(从而把区块串成区块链)、区块中所有交易的摘要、时间、nonce 等等。其中的 nonce 类似随机数,是挖矿的核心。我们在打包完交易,计算出区块头部剩余的字段之后,需要不断地调整 nonce,找到一个 nonce 满足
$$ \text{SHA256d}(\text{BlockHeader}) \leq \text{CurrentTarget} $$ 其中,$\text{CurrentTarget}$ 是一个全网公认的目标值,直接决定了挖矿的难度,其值越小,上式满足的概率越小,全网的挖矿难度就越高。挖矿的难度会根据出块速度每 2016 个区块(通常是 2 周)调整一次,从而控制出块速度在 10 分钟/块。
![](difficulty.png)
图源:blockchain.com
$\text{SHA256d}$ 是对消息连续做两次 SHA-256,即
$$ \text{SHA256d}(m)=\text{SHA256}(\text{SHA256}(m)) $$ 做两次 SHA-256 的目的通常被认为是为了防止长度扩展攻击(length extension attack),篇幅原因就不展开了,如果感兴趣可以单独写一篇文章。实践中,用 SHA-256d 代替 SHA-256 也是更推荐的做法。
因为结果是随机的,所以挖矿的过程可以看成是买彩票。比特币的全网算力已经达到了 160 EH/s,也就是全网每秒会进行 $160 \times 10^{18}$ 次 nonce 尝试,这个数字足够大到能够应用大数定律。
![](hash-rate.png)
图源:blockchain.com
要计算你能够挖到矿的概率,只需要用你的挖矿设备的算力除以全网算力即可。就目前而言,个人挖矿者想要挖到比特币几乎是不可能的。一部分人用 FPGA 或者自研专门的挖矿芯片来挖矿;另一部分人整合个人挖矿者的算力,形成「矿池」,挖到币后按照每个人贡献的算力进行分成。
最终一致性 🔗
发现新区块之后,新区块会被广播到比特币的分布式网络中。考虑到传播的延迟,一定会出现多个人「同时」广播了不同的合法区块的情况。有些节点可能接受了区块 A,有些节点可能接受了区块 B。在这种情况下,区块链就形成了分叉。
正如前面所说的,分叉是不可避免的。但是分叉没有问题,接受了区块 A 的节点会在区块 A 的基础上继续构建下一个区块,而接受了区块 B 的节点会在区块 B 的基础上构建下一个区块。当其中某个阵营优先发现新区块的时候,对应的那条分叉长度就增加了,变成了主链;而在另一条分叉上工作的节点会放弃那条短的分叉,跑回主链上。
这种一致性模型在分布式网络中被称为最终一致性(eventual consistency)。
总结 🔗
很多人问我比特币的价值是什么,我也不知道准确的答案。与金属货币不同,信用货币本身并没有使用价值,只具有流通价值,其核心是一种「信任」。比特币也是一样,它的价值很大程度上取决于多少人愿意信任它、流通它。
比特币基于分布式网络和密码学构建了一套「去中心」的货币系统,这是一种对「无人干预」的货币系统的尝试。在此之前我们可能没有意识到,信任的对象除了人和机构之外,还可以是一套完全自动化运作的分布式加密系统,这也是我觉得比特币最具魅力的地方。
比特币也不是不存在问题:共识机制建立在工作量证明的基础上,挖矿需要耗费大量的电力;算力越来越集中于一些大矿场,虽说要达到全网 51% 的算力从而控制区块链还是非常困难的(而且会因为比特币的信任崩塌导致他们手中的比特币也变得分文不值),但是个人挖矿者几乎不可能挖到比特币;每个区块的产生需要 10 分钟,即便立马被矿工打包,由于「最终一致性」,我们也还需要再等待几个区块,以确保它真正进入主链,因此整个交易从发出到被全网接受的时间比较长;更麻烦的是,比特币网络面临可扩展性问题(bitcoin scalability problem),区块大小是有限制的,出块速度又是恒定的,意味着单位时间内能够处理的交易数量也是有限的。
当然,比特币也在不断改进,比如为了解决可扩展性问题提出了闪电网络(Lightning Network),也出现过放宽,甚至取消区块大小限制的提案。另一个赛道上,一些新型的加密货币在尝试不同的共识机制。加密货币的未来会怎样?让我们拭目以待。