比特币开发指南——挖矿
挖矿添加新的区块到区块链中,使得交易历史很难被改变。目前的挖矿有两种形式:
- 独立挖矿:矿工试图独立生成新的区块,从而来自区块奖励和交易费用的收益全部归属于自己,允许他以更高的风险波动接受更高的回报(回报周期长)
- 合伙挖矿:矿工相互联合组成矿池发现更多的区块,根据他们贡献的hash算力共享收益,允许矿工以更低的风险波动接受较小的回报(回报周期短)
独立挖矿
如下表所示,独立矿工典型地使用getcoind
从网络中获取新的交易。他们的挖矿软件周期性地轮询bitcoind
,获取使用了getblocktemplate
RPC的新交易。getblocktemplate
RPC提供了新交易的列表和币基交易要发送到的公钥。
挖矿软件使用模板(如下所述)构造区块并创建区块头。然后发送80字节的区块头和一个目标阈值(难度设定)给挖矿硬件(ASIC)。挖矿硬件迭代区块头nonce的每种可能的值并生成相应的hash。
如果没有hash低于阈值,挖矿硬件从挖矿软件获得一个具有新的merkle root的更新的区块头。这个新的区块头是通过添加额外的nonce数据到币基交易的coinbase字段中创建的。
另一方面,如果hash被发现低于目标阈值,挖矿硬件返回带有成功nonce的区块头给挖矿软件。挖矿软件将区块头和区块组合起来,并发送完整的区块给bitcoind
广播到网络中,添加到区块链上。
合伙挖矿
加入矿池的矿工遵循相似的工作流程,如下表所示,允许矿池操作者基于矿工共享的工作量支付给矿工。矿池使用bitcoind
从网络中获取新的交易。使用后续讨论的方法之一,每个矿工的挖矿软件连接到矿池并请求需要的信息构建区块头。
在合伙挖矿中,矿池设置目标阈值比网络难度高出几个量级(难度降低)。导致挖矿硬件返回许多区块头,这些区块头并没有hash成一个有资格加入区块链的值,但是要比矿池的目标阈值要低,证明(平均)了矿工校验了一定比例的可能的hash值。
矿工然后给矿池发送一份矿池需要验证的信息副本——头部低于目标阈值而且被头部merkle root字段引用的交易的区块对于矿池的目的是有效的。(这通常意味着币基交易必须支付给矿池)
矿工发送给矿池的信息叫做共享因为它证明矿工做了一部分共享工作。有时候,一些共享矿池会收到低于网络目标难度的值——矿池发送这些到网络中被添加到区块链。
来自矿池的区块奖励和交易费是区块支付给矿池的。矿池将这些收益的部分基于矿工贡献的算力分配给他们。例如,如果矿池的目标阈值是100次,比网络目标阈值更低,将平局需要100个共享创建一个成功的区块。所以矿池会支付每个共享1%100的收益。不同的矿池基于基础共享系统使用不同的奖励分发系统
区块原型
在独立和合伙两种挖矿模式中,挖矿软件需要获取必要的信息构建区块头。本子章节以线性方式描述了信息是如何传递和使用的。然而,在实际的实现中,并行线程和队列被用于保证ASIC hash器以最大容量工作。
getwork RPC
最简单和最早但是现在已经过时了的方法就是比特币核心getwork
RPC,直接为矿工构建了一个头部。因为头部仅包含一个独立的4字节的nonce(能承担大概4千兆),许多现在的矿工需要每秒发出成百上千的getwork
请求。独立矿工在0.9.5或更低版本可能仍需要使用getwork
,但是今天的大部分矿池不鼓励或不允许使用它。
getblocktemplate RPC
一个改进的方法就是比特币核心getblocktemplate
RPC。给挖矿软件提供更多的信息。
- 必要的构建支付给矿池或独立矿工的
bitcoind
钱包的币基交易的信息。 - 交易
bitcoind
的彻底转储或矿池建议加入到区块中,允许挖矿软件检查交易,选择性地添加额外的交易和移除不强制要求的交易。 - 其他必要的构建下一个区块的区块头的信息:区块版本、前一个区块的hash和bits(阈值)
- 矿池的当前接受共享的目标阈值(对于独立节点,是网络目标阈值)
使用接收到的交易,挖矿软件添加一个nonce到币基额外的nonce字段,然后将所有的交易转换成merkle树派生可在区块头使用的merkle root。不管何时额外的nonce字段需要改变,挖矿软件都要重构merkle树的必要部分并更新区块头部中的时间和merkle节点字段。
像所有的bitcoind
RPC一样,getblocktemplate
是通过HTTP发送。为了确保他们得到最新的工作,大部分矿工使用HTTP 长轮询保持getblocktemplate
请求一直开启。允许矿池给矿工推送一个新的getblocktemplate
,只要任意P2P网络中的节点发布一个新的区块或矿池想要给挖矿软件发送更多的交易信息。
层级
一个广泛使用的getblocktemplate
的替换物就是层级挖矿协议。层级集中在给矿工构建区块头部需要的最少的信息。
- 必要的构建支付给矿池的币基交易的信息
- 当币基交易使用新的额外的nonce更新时,需要重新hash创建一个新的merkle root的merkle树的部分。merkle树的另一个部分,如果存在且尚未发送的话,有效地限制当前交易量要发送的最大的数据量(千字节)。
- 所有为下一个区块构建区块头必要的非merkle root信息
- 矿池的当前接受共享的目标阈值
使用接收到的币基交易,挖矿软件添加一个nonce到币基的额外的nonce字段,hash该币基交易,并把hash结果添加到接收到的merkle树的部分。树被hash创建merkle root,root要被加入到接收到的区块头信息中。无论何时额外的nonce字段需要被改变,挖矿软件更新并重新hash该币基交易,重新构建merkle root并更新头部merkle root字段。
不想getblocktemplate
,使用层级的矿工不能检查或添加交易到他们当前正在挖的区块中。也不像getblocktemplate
,层级协议直接使用两种TCP套接字方式,所以当新区块被广播到P2P网络中时,矿工不需要使用HTTP长轮询确保他们从矿池接收到即时的更新。