主页 > 苹果版下载imtoken > PoW挖矿算法原理及其在比特币和以太坊中的实现
PoW挖矿算法原理及其在比特币和以太坊中的实现
PoW,全称是Proof of Work,即工作量证明,又称挖矿。 大多数公链或虚拟货币,如比特币和以太坊,都是基于 PoW 算法来实现其共识机制。 即货币的分配是根据挖矿贡献的有效工作量来决定的。
比特币区块由区块头和区块中包含的交易列表组成。 区块头大小为80字节,其组成包括:
4字节:版本号
32字节:前一个区块的哈希值
32字节:交易列表的Merkle根哈希
4字节:当前时间戳
4字节:当前难度值
4字节:随机数Nonce值
这个 80 字节的区块头是 Bitcoin Pow 算法的输入字符串。
交易列表附加在区块头之后,第一笔交易是矿工获得奖励和手续费的特殊交易。
bitcoin-0.15.1源码中的区块头和区块定义:
Pow的过程就是不断调整Nonce值,对区块头进行两次SHA256哈希运算,使得结果满足给定个数前导0的哈希值的过程。
前导 0 的数量取决于挖矿的难度。 前导0越多,挖矿难度越大。
详情如下:
1. 生成一个铸币交易,与所有其他要打包到区块中的交易组成一个交易列表,并生成一个Merkle根哈希值。
2. 区块头的Merkle根哈希值和其他字段组成区块头,80字节的区块头作为Pow算法的输入。
3、不断改变区块头中的随机数Nonce,对改变后的区块头进行两次SHA256哈希运算,并与当前难度的目标值进行比较。 如果小于目标难度,则 Pow 完成。
Pow 完成的区块向全网广播,其他节点将验证其是否符合规则。 如果验证有效,其他节点将收到该块并将其附加到现有的区块链上。 然后进入下一轮挖矿。
bitcoin-0.15.1源码中Pow算法的实现:
附上bitcoin-0.15.1生成铸币交易和创建新区块的源码:
每创建2016个区块就会计算一个新的难度,新的难度将用于接下来的2016个区块。 计算步骤如下:
1.找到前2016个区块中的第一个区块,并计算生成这2016个区块所花费的时间。
即最后一个区块的时间与第一个区块的时间之差。 时差不少于3.5天且不超过56天。
2.计算前2016个区块的难度之和以太坊计算公式,即单个区块的难度x总时间。
3、计算新的难度,即2016个区块的难度之和/14天的秒数,得到每秒的难度值。
4.需要新的难度,且难度不低于参数定义的最低难度。
bitcoin-0.15.1源码中计算挖矿难度的代码如下:
一个以太坊区块由两部分组成,头部和主体。
Header部分的成员如下:
ParentHash,父块哈希
UncleHash,叔块哈希,具体为Body中Uncles数组的RLP哈希值。 RLP哈希,即对某类对象进行RLP编码后进行SHA3哈希运算。
Coinbase,矿工地址。
Root,StateDB中状态Trie的根节点的RLP哈希值。
TxHash,区块中tx Trie根节点的RLP哈希值。
ReceiptHash,Block中Receipt Trie根节点的RLP哈希值。
难度,区块难度,即当前挖矿难度。
Number,区块编号,即父区块Number+1。
GasLimit,区块中所有Gas消耗的理论上限,在创建时指定,由父区块GasUsed和GasLimit计算得出。
GasUsed,区块内所有交易执行时消耗的Gas总和。
时间,当前时间戳。
Nonce,随机数Nonce值。
关于叔块:
叔块,即孤立块。 以太坊的区块形成速度比较快,产生了孤块。
以太坊会奖励发现孤块的矿工,激励矿工在新区块中引用孤块,引用孤块使主链更重。 在以太坊中,主链是最重的链。
关于状态 Trie、tx Trie 和 Receipt Trie:
state Trie,所有的账户对象都可以一个一个插入到一个Merkle-PatricaTrie (MPT)结构中,形成一个state Trie。
tx Trie:将Block中Transactions中的所有tx对象逐一插入到MPT结构中,形成一个tx Trie。
Receipt Trie:区块中所有Transaction执行完毕后,生成Receipt数组,将所有Receipt逐一插入到MPT结构中,形成Receipt Trie。
机构成员如下:
交易,交易清单。
Uncles,引用的叔块列表。
go-ethereum-1.7.3源码中的区块头和区块定义:
以太坊 Pow 算法可以表示为以下公式:
兰德(h,n)
其中,RAND()代表一个概念函数,代表一系列复杂的运算。
其中h和n为输入,即block Header的hash和Header中的Nonce。
M代表一个非常大的数,这里用2^256-1。
d,是区块的难度,即Header中的Difficulty。
因此,当h和n确定后,d越大,越难挖,这就是Difficulty的本意。
即不断改变Nonce,使得RAND(h, n)满足RAND(h, n)
go-ethereum-1.7.3源码中Pow算法的实现:
以太坊每次挖矿都需要计算当前区块的难度。
根据不同的版本,计算难度的规则有3种,分别是:calcDifficultyByzantium(拜占庭版)、calcDifficultyHomestead(Homestead版)、calcDifficultyFrontier(Frontier版)。 这里以 calcDifficultyHomestead 为例。
计算难度的输入是:
parent_timestamp:父块时间戳
parent_diff:父块难度
block_timestamp: 当前区块时间戳
block_number:当前区块序号
当前区块的难度计算公式为:
其中,//为整数除法运算符a//b,即先计算a/b以太坊计算公式,然后取不大于a/b的最大整数。
调整难度的目的是将挖矿时间控制在10-19s以内。 小于10s会增加挖矿难度,大于19s会降低挖矿难度。 另外,云主机域名开发前计算出的区块难度不应低于以太坊创世区块的难度,即131072。
go-ethereum-1.7.3源码中计算挖矿难度的代码如下:
Pow 算法的概念很简单,就是工作端提交难以计算但易于验证的计算结果,其他节点验证这个结果,以确保工作端完成了相当大的工作量。
但其缺点也很明显: 1、随着节点将CPU挖矿升级为GPU甚至矿机挖矿,节点数量和算力逐渐变得不平衡; 2. 比特币等网络每秒需要完成数百万亿次运算的Hash计算,大量资源浪费。
为此,业界提出了一种替代 Pow 的方案如 PoS 权益证明算法,该算法要求用户拥有一定数量的币,才有资格参与决定下一个合法区块。 此外,相对于51%的算力,购买一半以上的币种难度更大,这也让恶意攻击变得更加困难。