Aaron 发表于 2018-03-09 09:34:34
文章来源:华为云社区
原文地址:https://bbs.huaweicloud.com/blogs/100427
本节讨论比特币最核心的部分,也就是比特币的共识机制——工作量证明(POW),是否理解工作量证明是你是否掌握比特币原理的分水岭,我读过很多关于比特币原理的文章,其中很大一部分关于比特币工作量证明的描述都是错误或者不完全的,所以你想了解某人是否清楚比特币原理,应该首先考察他对工作量证明的理解程度。
在详细描述比特币的工作量证明前,我们有必要先聊一下密码学哈希函数。
哈希函数是一个数学函数,具有以下三个基本特性:
1.输入可以是任意大小的字符串
2.产生固定大小的输出
3.对于特定的输入字符串,在合理的时间内可以算出哈希函数的输出
以上特性仅仅适用于一般的哈希函数,对于加密的哈希函数还需要四个附加特性:
1.碰撞阻力:如果无法找到两个值,x和y,x≠y,而H(x)=H(y),则称哈希函数H具有碰撞阻力。
这里要特别注意,无法找到碰撞不代表不存在碰撞,从前面的基本特性可知哈希函数的输入通常是任意长度的,而输出确是固定长度的。假设输出长度为256位,理论上如果给出2的256次幂+1个不同的输入,必然会产生碰撞。
但是目前对人类来说这是一个天文数字,换一种说法,假设人类制造的所有计算机在宇宙起源便开始计算,到目前为止,找到该碰撞的概率仍然趋近于无穷小。
2.隐秘性:在仅知道y=H(x)的情况下,无法算出输入值x(x必须来自于一个分散的集合)。
隐秘性保证哈希函数是一种单向函数,无法被反向计算。
3.谜题友好:对于H(x)=y,如果已知y,没有一个解决策略比只是随机的尝试x取值更容易找到x值,称这个哈希函数是谜题友好的。
这个特性保证了哈希函数的计算除了不断重复尝试,也就是暴力计算,没有其他捷径,对于比特币的挖矿是很重要的特性。
4.雪崩效应:当哈希函数的输入值发生极微小的改变时,也会导致输出结果的剧变。
雪崩效应保证了哈希函数输出结果具有较好的随机化特性,使其难以仅从输出结果推测输入值。
比特币中广泛采用的哈希函数是SHA-256(Secure Hash Algorithm 256),输出的长度是256位,这个哈希函数是由美国国家安全局(NSA)所设计(哈希函数的原理属于密码学范畴,不在我们的讨论范围内)。在比特币发布的2009年,SHA-256是当时最先进的哈希加密算法,在这之后NSA又发布了SHA-384,SHA-512等更安全的加密算法(输出位数越多,找到碰撞就越困难)。
SHA-256在比特币中被广泛应用,总结下SHA-256函数在比特币中使用的位置:
•工作量证明
•比特币公钥转换为公钥哈希
•交易的输入输出部分(Transaction id,交易脚本等)
•比特币区块头Previous Block Hash
•Merkle树
比特币的工作量证明
比特币的工作量证明是通过变动区块头(Block header)中的Nonce值,不断计算具有不同Nonce值的区块头哈希值,直到找到一个哈希值小于指定的难度值,通过发布这个结果来证明自己完成的工作量。
我们回顾一下比特币区块头的结构:
Size |
Field | Description |
4 bytes | Version | 区块版本号,目前为2 |
32 bytes | Previous Block Hash | 前置区块(父区块)的区块头Hash,Hash算法为double-SHA256 |
32 bytes | Merkle Root | 区块中交易Merkle树根 |
4 bytes | Timestamp | 区块创建UNIX时间戳 |
4 bytes | Difficulty Target | 工作量证明算法难度 |
4 bytes | Nonce | 通过变动该计数器来达成工作量证明要求的结果 |
从区块头的结构中可以看到一个4 bytes的Nonce值,Nonce值的变动会影响整个区块头的哈希值,挖矿节点即是通过尝试不同的Nonce值(通常从0开始每次加1),寻找一个哈希值小于Difficulty Target指定的难度值。
下面举个简单的例子
假设现在有一个字符串为“Satoshi Nakamoto is my dad.”,我们设定一个目标:通过在这句话末尾加上数字来计算一个哈希值,这个哈希值的十六进制表示以00开头。
Satoshi Nakamoto is my dad.0 => 90c27bad9a86c1eb6357a9f651ab0e2fb308616e7ea0f9720d7a255491c181bc
Satoshi Nakamoto is my dad.1 => edd3247a8c56979d7741f8e98d18d729c4336f4a0234b3fd6fae3c3a943f0b6a
Satoshi Nakamoto is my dad.2 => 2b622e4cf522982bd2c7c087640e6024d856875bab97ff6329df42c19254f131
Satoshi Nakamoto is my dad.3 => cafff550474d1af4757001a5e907f74ab63607fa8bf324838d8dec530be86f0a
Satoshi Nakamoto is my dad.4 => d8468facea81c3c5964f0728f321bccbc1d76a00a23261ef158290f9ce694375
Satoshi Nakamoto is my dad.5 => f166cd0d391d1130fa866c5e9f935392dd6563f29e8e860f6e7245c43cba6c9f
Satoshi Nakamoto is my dad.6 => b2f255fe5d91abf496bafd12988283a745bd1131e223f37a7bcb8e2517636c15
Satoshi Nakamoto is my dad.7 => b53d901baf3b621362b6a1de6e0f435182b2fda45b305446f0c29b45f00c6d9f
Satoshi Nakamoto is my dad.8 => e8d41c9d69119890377983da4da97b307339a05ee3a601aeb82645422d4eab1e
Satoshi Nakamoto is my dad.9 => 008015b7e59b53a34b60785b4722002a1d7a4134e4970957beaac7fe8969ac42
最终经过10次计算,我们找到了数字9可以得到00开头的哈希值,完成了该工作量证明的哈希计算。
比特币挖矿的挑战与上例类似,区块头信息即为“Satoshi Nakamoto is my dad”,后面添加的数字9即是Nonce值。可以预知,如果我们选择的目标值开头0的个数越多,找到结果的难度就越高。
挖矿难度目标与难度调整
比特币挖矿难度调整方式非常简单,难度目标调整即不断将256位的难度值减小,如277315号区块的难度值十六进制表示为:
0x0000000000000003A30C00000000000000000000000000000000000000000000
这个数字在二进制表示下前60位均是0,如果要增加难度只需要减小这个值,随着难度值的减小,起始0的个数增多,可寻找的哈希值范围减小,挖矿难度就越大。
那么问题来了:这个难度值由谁来调整?如何调整?
比特币要使出块速率恒定保持在平均10分钟一个,而随着挖矿算力飞速增加,挖矿难度必须根据这些变化进行调整。
挖矿难度的调整是在每个完整节点中独立完成的,每过2016个区块(约2周)所有节点会检查并调整一次难度,各节点会将2016个区块的总出块时间与20160分钟比较,如果大于20160分钟则降低难度,如果小于则提升难度。
难度调整的公式为:
New Target = Old Target * (Actual Time of Last 2016 Blocks / 20160 minutes)
为防止难度变化过大,每个周期的调整幅度不能超过4倍,如果算力变化超过4倍,多余的部分将在下一个周期调整。
注:虽然目标调整每2,016个块发生,但是由于Bitcoin Core客户端的一个错误,实际是基于之前的2015个块的总时间(不是2016个),导致调整偏差向较高难度提高0.05%。
当某一挖矿节点成功在第一时间找到使区块头哈希值小于目标值的Nonce值时,就将该Nonce写入区块头并立刻广播给相邻的节点,其他节点验证无误后就会将新区块记录到区块链上,并开始尝试完成下一个区块的工作量证明。
如277315号区块的Nonce值为4215469401,区块头哈希值为:
0000000000000002a7bbd25a417c0374cc55261021e8a9ca74442b01284f0569
这个值小于难度目标值:
0000000000000003A30C00000000000000000000000000000000000000000000
值得进一步思考的问题
1.观察一下区块头的结构,你是否想过所有节点的区块头内容似乎都是一样的,这种情况下如果所有节点都从0开始尝试Nonce值,那不就永远都是算力高的节点先计算出有效的结果,算力低的节点永远没希望挖矿成功?
答案显然是否定的,我们再仔细看下区块头的结构,确实大部分信息都是一样的,但是Merkle Root对于每个节点必然是不同的,从上一节的内容可以知道每个节点都会有自己的Coinbase交易,该交易中存在节点矿工的地址,此地址对于每个独立挖矿节点都是不同的,根据哈希函数的雪崩效应可知每个独立节点的Merkle Root必定有显著的区别。
2.比特币的工作量证明计算有一个重要的特点,即是难于计算,却易于验证,每次完成工作量证明需要大量的哈希计算,但是验证只需要一次哈希计算,使得各节点对于结果能很有效率的达成共识。
工作量证明在我们的平时生活中其实经常发生,比如我们的考试成绩、毕业证、技能认证都是一种工作量证明,这其实是对于付出努力的一种证明。这些东西可能会较难获取,但是非常容易验证,大大提高了社会的信任效率。
3.在上一节了解到如果按照平均每十分钟产出一个区块计算,比特币理论上不再产生新币的时间约为2140年,当时我说过这个时间有可能会被提前,原因就在于挖矿难度的调整并不是实时的,而是每2016个区块调整一次。试想如果算力提升速度较快,会使区块生成速度加快,那2016个区块的产生时间会经常低于20160分钟,最终产出2100万比特币的时间也就会缩短。
4.了解完工作量证明后,这时候恐怕你会认为比特币挖矿节点为了竞争记账权不断完成哈希计算,这种计算对人类似乎毫无价值,是一种资源浪费。在这里我提供一些辩证的想法给大家参考:
(1)比特币的挖矿表面上看目的是为了获得比特币奖励,但实际的功能是让比特币网络变得更安全。现实生活中我们为了安全(网络安全、财产安全、人生安全……)付出巨大的代价,为什么没有人觉得这是一种浪费?
(2)比特币网络自主完成安全的铸币、交易等等一系列工作,在现实生活中这些工作通常是由银行完成,银行的经营也要付出巨大的成本,为什么没有人觉得银行是一种浪费?
(3)人们努力寻找和挖掘黄金,往往只是因为它值钱,和比特币矿工的逐利思维是一样的。挖黄金还破坏自然环境,比特币挖矿却通常使用可再生能源,还使很多电力过剩的电厂扭亏为盈,产生了新的就业机会。为什么没有人觉得挖黄金更浪费资源?
说到底我们很容易被眼前已经固化的事实所蒙蔽,对新事物的本质总是无法理解,并产生天然的抗拒。对人类来说信任必然是有代价的,而挖矿消耗的资源就是这种代价,资源消耗越多(矿工越多)这种信任越牢固(去中心化程度越高)。
当然我也很希望看到未来有技术可以使得挖矿所耗费的算力被利用起来,现在也已经有一些尝试,如将算力用来寻找素数,用于作人工智能计算等等。或者有更好的共识算法能减少资源的消耗,现在的POS,DPOS等算法都是这方面的尝试,但是否真的更好还有待时间的验证。
综上所述,我认为我们真的不应该以此来批评比特币挖矿,单纯的认为比特币挖矿就是浪费资源是不正确的。
好了,恭喜你,你已经理解了比特币去中心化体系最重要的部分——POW共识机制,并且还了解了我对于比特币挖矿长时间思考的见解,希望对你有帮助。未来我们会讨论更多的共识算法,加油!