挖矿 - 比特币开发指南
原文链接: https://bitcoin.org/en/developer-guide#operating-modes
翻译: terryc007
版本:1.0
比特币开发指南
1. 区块链
2. 交易
3.合约
4.钱包
5.支付处理
6.工作模式
7.P2P网络
8.挖矿
挖矿就是把新的区块加到区块链上,这使得很难去修改交易记录。目前有两种挖矿方式:
单独挖矿(Solo): 矿工自己生成新区块,独自从区块奖励,交易费用获取收入,这使得他可以获得大额的支付(支付时间长)。
矿池挖矿(Pooled): 矿池里的矿工通常一起挖矿,每个矿工根据其在矿池中贡献的算力来平分收益,每个矿工会收到小额的支付(支付时间短)。
单独挖矿
如下图所示,solo挖矿通常使用bitcoind
从比特币网络获取新的交易。他们的挖矿软件定期的使用getblocktemplate
PRC轮询bitcoind
来获取新的交易,并返回新的交易列表,以及coinbase交易被发送到的公钥。
挖矿软件使用区块模板构建一个区块,并创建一个区块头。然后它发送带有难度目标阀值的,80字节区块头到挖矿硬件(比如ASIC)。挖矿硬件为区块头nonce尝试各种可能的值,并生成相应的哈希。
如果没有任何哈希低于设置的目标阀值,挖矿硬件会从挖矿软件那里获取一个带有新的默克尔根的,更新过的区块头。新的区块头是通过在coinbase交易的coinbase字段加入额外的nonce数据来产生的。
另一方面,如果找到一个哈希值低于目标阀值,挖矿硬件会把成功的nonce区块头返回给挖矿软件。挖矿软件把区块头跟区块组合起来,然后把完成的区块发送给bitcoind
,bitcoind
再把区块广播到比特币网络。
矿池挖矿
矿池挖矿的流程跟solo挖矿流程类似,如下图所示,矿池运营者基于每个矿工完成的工作量来给他们支付。矿池使用bitcoind
从比特币网络获取新的交易。使用下面会讲到的方法,每个矿工的挖矿软件会连接到矿池,并从矿池哪里获取它所需要的信息来构建区块头。
在矿池挖矿中,矿池会会把目标阀值设的比比特币网络难度低一些。这了会导致挖矿硬件会返回很多区块头,但这些区块头的哈希值是不合格的,并不能加入到区块链,但是他们的哈希值却符合矿池设置的目标阀值, 这可以用来证明(平均上)矿工的确是完成了一定比例的哈希计算。
然后矿工给矿池发送一些信息,矿池用它来验证他们生成的区块头的哈希值是否低于目标阀值,并且验证与区块头默克根字段相关的交易,他们所在的区块是否有效。(这通常意味着coinbase交易必须支付给矿池)
矿工发送给矿池的信息被称为share,因为它证明矿工完成了一部分工作。偶尔,矿池收到的shares也会低于比特币网络目标阀值 — 矿池会把这些区块发送到比特币网络,以便它们可以被加入到区块链。
从挖矿而获得区块奖励,交易费用需要支付给矿池。然后矿池了会基于每个矿工生成shares的多少,给每个矿工支付收益。比如,如果矿池目标阀值低于网络目标阀值的1/100, 那么要成功挖出一个区块,平均需要生成100份share,因此矿池可以给每个share支付1/100的收益。 基于基本的share系统,不同的矿池使会使用不同的分布式系统。
区块原型
在solo跟矿池挖矿这两种方式中,挖矿软件需要获取一些必要的信息来构建区块头。本节讲述的信息如何传输,使用,都是线性的。 而在实际实现中,会使用并发线程,队列让ASIC哈希计算器保持满负荷工作。
getwork RPC
在比特币内核,矿工使用最简单,易用的方法getwork
PRC来构建区块头,不过这个方法目前已经废弃掉。因为一个区块头只包含4字节的nonce,对应约4G哈希算力,但是现代的矿机需要每秒发起上百个getwork
请求。Solo矿工还可以用比特币内核v0.9.5或更低版本来挖矿,但是目前大部分矿池不鼓励或者不允许使用。
getblocktemplate RPC
getblocktemplate
RPC是比特币内核中一个改进的方法。它给挖矿软件提供了很多信息:
用于支付矿池而构建一个coinbase交易或solo矿机的
bitcoind
钱包,所需要的信息。bitcoind
上所有交易的dump或者矿池交易加入到区块中的交易,这就允许挖矿软件可以对交易进行检查,有选择的加入一些交易,删除一些不需要的交易。其他用于为下一个区块构建一个区块头所需要的信息: 区块版本号,之前区块哈希值,bits(目标阀值)
矿池当前的目标阀值,用于接收shares。(对于solo矿工而言,这是网络目标阀值)
挖矿软件使用收到的交易,加上一个nonce在coinbase 额外nonce字段上,然后把所有的交易转化默克尔树,并派生出用在区块头的默克尔根。不管何时,只要额外nonce字段有修改,挖矿软件会重新构建默克数中必要的部分,更新区块头中的时间,默克根字段。
像所有的bitcoind
RPCs,getblocktemplate
都是通过HTTP发送。 为确保矿工能获取到最近的工作,大部分矿工使用HTTP longpoll,让getblocktemplate
请求一直运行。这样了,任何在P2P网络的矿工一发布一个新的区块,或者矿池想发送更多的交易给挖矿软件,矿池就可以给矿工推送一个新的getblocktemplate
消息.
Stratum
Stratum挖矿协议是另外一个被广泛使用的挖矿方式。 Stratum专注于给矿工提供最少必要的信息,让矿工自己来构建区块头。
用于构建coinbase交易来支付矿池,所需信息。
部分默克尔树。 当coinbase交易更新了一个新的额外nonce,通过部分默克尔树重算哈希,来创建新的默克根。
其他必须的,非默克尔根信息,用来构建下一个区块的区块头。
矿池当前目标阀值,用来接收shares
挖矿软件使用收到的coinbase交易,添加一个nonce到coinbase额外交易noce字段,对coinbase交易进行哈希,把这哈希结果添加到默克尔树接收到部分。根据需要对默克尔树哈希计算来创建默克根,并把它加入到收到的区块头。不管什么时候,只要额外nonce字段发生改变,挖矿软件会更新,重新对coinbase交易哈希,重建默克根,并更新区块头的默克根字段。
不像getblocktemplate
, 使用Stratum的矿工,是不能检查,添加交易到他们目前正在挖的区块中。 也不像getblocktemplate
那样,Stratum协议直接使用双向TCP socket, 因此当一个新的区块广播到P2P网络时,矿工不必使用HTTP longpoll来确保时刻能收到矿池发来的更新。
资源: BFGMiner GPLv3 和 EloipoolAGPLv3 是目前在矿工,矿池中,被广泛使用的挖矿软件。 libblkmaker C 库 和 python-blkmaker 都是基于MIT licensed, 实现了GetBlockTemplate功能的代码库。
声明:
文中带有[?]的地方,表示我对此翻译明显感觉不太对的,后续会不断修正。
有些地方可能会翻译的不好,不地道,甚至错误,如果有发现,还请留言,指出,以便我好修正,谢谢!