本文详细解释了比特币的挖掘,包括十六进制数据和网络流量。如果您曾经想知道比特币挖矿到底发生了什么,那么您来对地方了。我的上一篇文章《比特币的艰辛》描述了我如何手动创建比特币交易并将其发送到系统中。在本文中,我展示了接下来发生的事情:如何将事务挖掘到一个块中。
采矿目的
比特币挖掘通常被认为是创建新比特币的方式。但这实际上只是次要目的。挖掘的首要重要性是确保所有参与者对比特币数据具有一致的看法。由于比特币是一个分布式的点对点系统,因此没有中央数据库可以跟踪谁拥有比特币。相反,所有事务的日志都分布在整个网络中。
分布式事务日志的主要问题是如何避免可能使某人花费相同的比特币两次的不一致之处。比特币中的解决方案是大约每10分钟将未完成的交易挖掘为一组交易,这使它们成为正式交易。不允许将有冲突或无效的交易分成一个大块,从而避免了重复消费问题。
尽管将交易挖掘成块可以避免双重支出,但它却带来了新的问题:是什么使人们无法随机开采块?您如何确定谁去开采街区?网络如何同意哪些块有效?解决这些问题是比特币的关键创新:挖矿变得非常非常困难,一种称为工作量证明的技术。挖掘一个块需要大量的计算工作,但是网络上的对等方很容易验证一个块是否已成功开采。
每个开采的区块都引用前一个区块,形成一条不中断的链回到第一个比特币区块。该区块链可确保每个人都同意交易记录。它还确保了没有人可以篡改链中的块,因为重新挖掘以下所有块在计算上是不可行的。只要没有人拥有超过一半的计算资源,挖掘就将保持竞争优势,并且没人可以控制区块链。
副作用是,采矿将新的比特币添加到系统中。对于每个开采的区块,矿工目前会获得25个新的比特币(目前价值约15,000美元),这鼓励矿工进行挖矿的艰苦工作。每10分钟可能会收到$ 15,000,因此挖矿的钱很多。
采矿如何运作
挖掘需要执行非常困难但易于验证的任务。比特币挖矿使用加密技术,其哈希函数称为double SHA-256。哈希将数据块作为输入并将其缩小为较小的哈希值(在这种情况下为256位)。使用密码哈希,就无法在不尝试大量输入的情况下获得所需的哈希值。但是,一旦找到可以提供所需值的输入,任何人都可以轻松验证哈希。因此,加密哈希成为实现比特币“工作量证明”的好方法。
更详细地讲,要挖掘一个区块,您首先需要将新交易收集到一个区块中。然后,您对块进行哈希处理以形成256位块哈希值。如果散列以足够的零开始[3],则说明该区块已成功开采,并已发送到比特币网络,并且散列成为该区块的标识符。大多数情况下,哈希无法成功执行,因此您需要稍稍修改该块,然后再尝试一次,超过数十亿次。大约每10分钟就会有人成功地挖出一个区块,然后过程重新开始。
下图显示了特定块的结构以及如何对其进行哈希处理。黄色部分是块头,后面是进入该块的事务。第一笔交易是特殊的币库交易,该交易将采矿奖励授予矿工。剩下的交易是标准的比特币交易,移动比特币。如果标头的哈希以足够的零[3]开头,则该块已成功开采。对于下面的块,哈希成功:0000000000000000e067a478024addfecdc93628978aa52d91fabd4292982a50
并且该块成为区块 链中的块#286819。
比特币区块的结构
块头包含一些描述块的字段。块中的第一个字段是协议版本。其后是区块链中前一个区块的哈希,以确保所有区块在区块链中形成不间断的序列。(不方便地,在标头中将哈希值颠倒了。)下一个字段是Merkle root,是该块中所有事务的特殊哈希值。这也是比特币安全的关键部分,因为它确保交易一旦成为区块的一部分就无法更改。 接下来是该块的时间戳(中等准确),其后是挖掘难度值bit。最后,随机数是一个任意值,每次尝试提供新的哈希值时都会递增。挖掘的棘手部分是找到一个有效的随机数。
ASIC比特币矿工
照片由Mirko Tobias Schaefer摄(CC BY 2.0)
一个简短的程序来挖块
我编写了一个Python程序来挖掘以上代码块。该程序本身非常简单-代码中最难的部分是根据位计算难度目标。[3]否则,这只是对不同随机数值的循环。每次迭代都会将数据放入一个结构中,对其进行哈希处理并测试结果。
下表显示了从选定的随机数值获得的哈希值。关键是每个随机数都会生成一个基本随机的哈希值。“幸运”随机数通常会生成从零开始的哈希值。要获得很多零,您需要尝试成倍数量的随机数。对于此块,“获胜”随机数为856192328。
随机数 | 杂凑 |
---|---|
0 | 5c56c2883435b38aeba0e69fb2e0e3db3b22448d3e17b903d774dd5650796f76 |
1个 | 28902a23a194dee94141d1b70102accd85fc2c1ead0901ba0e41ade90d38a08e |
2 | 729577af82250aaf9e44f70a72814cf56c16d430a878bf52fdaceeb7b4bd37f4 |
3 | 8491452381016cf80562ff489e492e00331de3553178c73c5169574000f1ed1c |
39 | 03fd5ff1048668cd3cde4f3fb5bde1ff306d26a4630f420c78df1e504e24f3c7 |
990 | 0001e3a4583f4c6d81251e8d9901dbe0df74d7144300d7c03cab15eca04bd4bb |
52117 | 0000642411733cd63264d3bedc046a5364ff3c77d2b37ca298ad8f1b5a9f05ba |
1813152 | 00000c94a85b5c06c9b06ace1ba7c7f759e795715f399c9c1b1b7f5d387a319f |
19745650 | 000000cdccf49f13f5c3f14a2c12a56ae60e900c5e65bfe1cc24f038f0668a6c |
243989801 | 0000000ce99e2a00633ca958a16e17f30085a54f04667a5492db49bcae15d190 |
856192328 | 0000000000000000e067a478024addfecdc93628978aa52d91fabd4292982a50 |
我应该指出,我从一个可以成功开采的地块开始作弊。大多数尝试挖掘一个块的尝试都会完全失败-没有一个nonce值会成功。在这种情况下,您需要稍微修改该块,然后重试。时间戳可以调整(这就是为什么在开采区中的时间戳通常是错误的)。可以将新事务添加到块中,从而更改Merkle哈希。可以修改币库交易-事实证明这对于采矿池非常重要。这些更改中的任何一个都会导致完全不同的哈希值,因此可以再次尝试使用nonce值。
我的Python程序每秒执行约42,000个哈希,这比实际矿工使用的硬件慢一百万倍。我的程序平均需要大约一千一百万年才能从头开始挖掘。
挖矿很辛苦
开采区块的难度令人震惊。在当前的困难下,哈希成功的机率比10 19中的几率小。与从地球上所有沙粒中找到特定的沙粒相比,找到成功的哈希值要困难得多。为了每十分钟查找一次哈希,比特币哈希率必须非常大。目前,比特币网络上的矿工正在每秒处理约2500万千兆ahashash。即,每秒散列大约25,000,000,000,000,000个块。我估计(非常粗略地),用于比特币开采的全部硬件花费了数千万美元,并且消耗的电力与柬埔寨国家一样多。
请注意,找到成功的哈希值是完全任意的任务,它本身不会完成任何有用的工作。找到一个小哈希的唯一目的是使挖掘变得困难,这对于比特币的安全至关重要。在我看来,最近投入到比特币开采的努力已经脱离了轨道。
采矿的资金主要来自每块25比特币的奖励,略有交易费用(每块约0.1比特币)的资金。由于采矿奖励目前的计算成本约为每块15,000美元,因此需要支付大量硬件。每笔交易,矿工可获得约34美元的采矿奖励和0.10美元的费用(统计数据)。
15 GH / s FPGA比特币采矿配置和41 Icarus。照片由刘翔夫允许
泳池采矿
由于采矿非常困难,因此通常在采矿池中完成,在那里一群矿工共享工作并分享回报。如果您自己进行开采,则可能会成功开采一个区块并每隔几年获得25个比特币。通过作为池的一部分进行开采,您每天可以获得一小部分比特币,这对大多数人来说是更可取的。
矿池使用一种有趣的技术来查看矿工的工作量。他们发出一个要开采的区块,每当矿工获得部分解决方案时,便从矿工那里获取更新。每个部分解决方案都证明了矿工正在努力解决该问题,并在某人成功开采区块时向矿工分享了最终的回报。
例如,如果比特币挖矿需要以15个零开头的哈希,那么挖矿池可以要求以10个零开头的哈希,这容易上百万倍。根据他们硬件的能力,矿工可能每隔几秒钟或每小时几次找到这样的解决方案。最终,这些解决方案之一将不仅以10个零开始,而且以15个零开始,成功地挖掘区块并赢得奖池。[7]然后,根据每个矿工的股份数量(占总数的一小部分)来分配报酬,而矿池运营商只占一小部分的间接费用。
大多数时候,泳池外有人会首先挖一个街区。在这种情况下,池操作员将发出新数据,而矿工将开始挖掘新区块。如果由于采矿业的运气不佳,很长一段时间没有付钱,游泳池里的人就会前卫。
阶层:矿池与矿工之间的交流
接下来,我将详细介绍矿工与采矿池之间的通信。矿池与矿工之间的交流很有趣。矿池必须有效地为矿工提供工作并迅速收集其结果。该池必须确保矿工没有重复工作。而且,矿池必须确保矿工不要浪费时间在已经开采的区块上工作。
矿池的一个重要问题是如何支持快速矿工。标头中的nonce字段对于快速矿工而言太小,因为它们将比池发送块更快地遍历所有可能的值。解决方案是允许矿工更新币库交易,以便他们可以在此处放置其他随机数。这使采矿变得更加复杂,因为在建立币库交易之后,矿工必须重新计算Merkle哈希树,然后尝试开采该区块。
我将研究许多池使用的Stratum采矿池协议。(一些替代协议是Getwork和Getblocktemplate协议。)以下Python程序使用Stratum协议向GHash.IO挖掘池发出挖掘请求并显示结果。(此程序只是一个最小的演示;请勿在实际挖掘中使用此代码。)
下面的信息是采矿池响应上述程序通过网络发送回的信息。由于Stratum协议使用 JSON-RPC, 因此结果是可读的ASCII而不是大多数比特币使用的二进制数据包。这提供了开始作为池一部分进行挖掘所需的所有数据: {“ id”:1,“结果”:[[[“ mining.set_difficulty”,“ b4b6693b72a50c7116db18d6497cac52”],[“ mining.notify”,“ ae6812eb4cd7735a302a8a9dd95cf71f”]],“ 4bc6af58”:,4], } {“ id”:null,“ params”:[16],“ method”:“ mining.set_difficulty”} { “ID”:NULL, “PARAMS”:[ “58af8d8c”, “975b9717f7d18ec1f2ad55e2559b5997b8da0e3317c803780000000100000000”, “01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4803636004062f503253482f04428b055308”, “2e522cfabe6d6da0bd01f57abe963d25879583eea5ea6f08f83e3327eba9806b14119718cbb1cf04000000000000000000000001fb673495000000001976a91480ad90d403581fa3bf46086a91b2d9d4125db6c188ac00000000”,[ “ea9da84d55ebf07f47def6b9b35ab30fc18b6e980fc618f262724388f2e9c591”, “f8578e6b5900de614aabe563c9622a8f514e11d368caa78890ac2ed615a2300c”, “1632f2b53febb0a999784c4feb1655144793c4e662226aff64b71c6837430791”, “ad4328979dba3e30f11c2d94445731f461a25842523fcbfa53cd42b585e63fcd”, “a904a9a41d1c8f9e860ba2b07ba13187b41aa7246f341489a730c6dc6fb42701”,”dd7e026ac1fff0feac6bed6872b6964f5ea00bd8913a956e6b2eb7e22363dc5c“,” 2c3b18d8edff29c013394c28888c6b50ed8733760a3d4d9082c3f1f5a43afa64“]”“ 00000053”,“ 53”“ {“ id”:2,“结果”:true,“错误”:null} {“ id”:null,“ params”:[16],“ method”:“ mining.set_difficulty”}
第一行是池服务器的响应,其中包含订阅详细信息。第一个值不太重要。该值4bc6af58
是构建块时使用的值extranonce1。每个客户端都会获得一个唯一的值,以确保所有采矿客户端都生成唯一的块,并且不会重复工作。以下值(4
字节)是矿工在挖矿时将其放入币库中的extranonce2_size值的长度。
第二行是向我们的客户发送的mining.set_difficulty消息。难度为16,我可以每隔一两个小时在PC上获得一个共享。相比之下,比特币的开采难度为3,129,573,174.52 [3] -因此,与独立地成功开采一个区块相比,在该池中获得份额要容易大约2亿倍。这就是人们加入泳池的原因。
第三行是向我们的客户的采矿通知通知。此消息为我们定义了该区块。在“参数”下返回了很多数据,因此我将逐个字段对其进行解释。
job_id | 58af8d8c |
prevhash | 975b9717f7d18ec1f2ad55e2559b5997b8da0e3317c803780000000100000000 |
硬币1 | 0100000001000000000000000000000000000000000000000000000000000000000000 0000000000ffffffff4803636004062f503253482f04428b055308 |
coinb2 | 2e522cfabe6d6da0bd01f57abe963d25879583eea5ea6f08f83e3327eba9806b 14119718cbb1cf04000000000000000000000001fb673495000000001976a914 80ad90d403581fa3bf46086a91b2d9d4125db6c188ac00000000 |
merkle_branch | [“ ea9da84d55ebf07f47def6b9b35ab30fc18b6e980fc618f262724388f2e9c591”,...] |
版 | 00000002 |
位数 | 19015f53 |
时间 | 53058b41 |
clean_jobs | 假 |
该JOB_ID是用来标识该挖掘任务,如果矿工报告回成功。
大部分字段都在块头中使用。该prevhash是的哈希先前块。显然,混合使用大尾数和小尾数还不够混乱,因此此哈希值还将每个4字节的块都反转了。的版本是块协议版本。所述NBITS表示难度[3]的块的。时间戳记ntime不一定准确。
该coinb1和coinb2域允许矿工打造为块coinbase交易。这种交易是通过连接形成coinb1,所述extranonce1在开始时获得的值,所述extranonce2该矿工已经产生,并且coinb2。结果是使用比特币协议进行交易。该merkle_branch散列表让矿工有效地与新coinbase交易重新计算哈希梅克尔。
如果矿工需要重启采矿作业,则使用clean_jobs。
接收到此数据后,矿工可以开始生成币库交易和挖掘区块。
Butterfly LabsJalapeñoASIC矿机,0xF2,7+ GH / s, (CC BY-ND 2.0)
为池创建一个块
一旦矿工从矿池接收到信息,就可以直接通过加入coinb1,exeronnce1,exernonce2和coinb2来形成币库交易来形成币库交易。下图显示了这四个值的组合如何形成完整的事务,并且现时值位于coinbase脚本的中间。(下面的块与前面描述的块略有不同。)
GHash.io矿池生成的一枚coinbase交易
Coinbase交易的结构类似于常规交易,但有一些重要区别。正常交易将比特币从输入(通常是源地址)转移到输出(通常是目的地址)。Coinbase交易是凭空产生新的比特币,而不是进行转移,因此交易略有不同。先前的输出哈希和索引与coinbase交易无关。第一个脚本是scriptSig,它对交易进行签名以证明传入比特币的所有权。在coinbase交易中,这是无关紧要的,因此该字段称为coinbase,并且大部分是任意数据。(许多矿工隐藏的消息在那里。)的值在coinbase交易场是25比特币采矿奖励加上从其他交易留下任何比特币(左过比特币被作为采矿费处理)。最后,常规交易和coinbase交易都使用第二个脚本(scriptPubKey)来指定比特币的接收者。 有关交易的详细信息,请参阅我的前一篇文章。
一旦创建了coinbase事务,该coinbase事务的哈希将与池中的merkle_branch数据合并,以生成整个事务集的Merkle哈希。由于Merkle哈希的结构(如下所述),因此可以轻松地重新计算整个交易集的哈希。
最后,从新的Merkle哈希和池提供的数据构建块头,并且该哈希算法可以迭代头中的nonce值,就像之前的Python程序一样。一旦尝试了所有的现时值,矿工就增加extranonce2,生成一个新的币基交易并继续。
比特币区块头
通知成功的矿池
挖矿池 的难度[3]设置为比比特币挖矿难度低得多(所需的前导零更少),因此获得份额要容易得多。当一个块被散列到池的难度中时,您将一个简单的JSON消息发送到挖掘池以提交它: {“方法”:“采矿提交”,“参数”:[“ kens.worker1”,“ 58af8db7”,“ 00000000”,“ 53058d7b”,“ e8832204”],“ id”:4}
参数是工作人员名称,作业ID,Extranonce2,时间和标头随机数。该信息足以使池构建匹配的coinbase事务和标头,并验证该块。如果哈希满足池难题,您将获得份额。如果哈希值也遇到了非常困难的比特币难度,则说明该区块已成功开采。在这种情况下,该池将区块提交给比特币网络,并且所有拥有股份的人都会相应地得到付款。
挖掘乐趣和利润
如果您对采矿感到好奇,尝试自己进行采矿就非常容易,尽管您很幸运甚至可以赚到一分钱。只需在诸如BTC Guild之类的采矿池中创建一个帐户,下载诸如cpuminer(minerd.exe)之类的挖掘软件,然后运行该软件即可开始挖掘。对于低难度的池,您应该在几分钟内获得份额;在难度较高的池中(例如GHash.IO),可能需要一两个小时才能获得共享,这更令人沮丧。[3]
我的PC上无法盈利的比特币CPU挖矿
上面的屏幕截图显示了在您获得份额和区块被开采时的开采情况。我很幸运,只花了我一分钟就成功获得了份额。一分钟后,有人成功开采了一个街区,因此游泳池告诉所有人重新开始。此后不到一分钟就开采了另一个区块-尽管区块平均相隔10分钟,但时间差异很大。我的下一个分享花了12分钟。运行一段时间后,我获得了0.00000043 BTC,这只是一美分的一小部分。
比特币采矿是一场“军备竞赛”。最初,人们可以在普通PC上使用CPU进行挖掘,但这已经有一段时间没有实际应用了。接下来的挖掘工作转移到了GPU。现在,使用专用ASIC硬件完成了挖掘,而专用ASIC硬件的速度正在迅速提高。营利性采矿竞争非常激烈,您需要在其他地方寻找信息。
如果您想只是为了娱乐而尝试挖掘,那么您可能更喜欢挖掘狗狗币之类的货币,而不是比特币。首先,Dogecoin使用不同的哈希算法,该算法无法与ASIC硬件一起很好地工作,因此与专业矿工相比,您并没有处于不利地位。其次,由于狗狗币的价值比比特币要少得多,因此最终您会得到更多的狗狗币,这似乎更有意义。对于Dogecoin挖矿,我任意使用了dogepool.pw池。除了使用scrypt算法而不是sha256d之外,该过程几乎与比特币挖掘相同。还有许多其他替代加密货币可供选择。