.. _mining: ******************************************************************************** 挖矿 ******************************************************************************** 简介 ================================================================================ 挖矿这个词起源于把加密货币类比于黄金,黄金或者贵金属的储量是有限的,加密货币也是如此,并且增加的唯一方法就是通过挖矿,以太坊在很大程度上也是如此,一旦进行了发布,以太币增加的唯一方式就是挖矿。但是又不同于黄金的例子,以太坊的挖矿过程同时也是确保创建、验证、发布和增加区块的安全的过程。 - 以太币挖矿 = 确保网络安全 = 验证计算 什么是挖矿? -------------------------------------------------------------------------------- 以太坊,同其它区块链技术一样,使用奖励-驱动的安全模型,共识机制是基于选择最高难度的区块,矿工们生产出可以被其它矿工验证通过的合法区块,初了必要的格式以外区块还必需满足给定 *难度* 的 *工作量证明* (PoW) ,在以太坊的特定里程碑Serenity后,工作量证明会被股权证明所取代(参考 :ref:`proof of stake model `)。 以太坊区块链同比特币区块链在很多方面都很相似,虽然也有一些差异,两者在架构上的最主要的差异就是,不同于比特币,以太坊区块链包含所有的交易链还有最近的状态(更准确的说是最近状态的默克尔帕特里夏树的根哈希),此外还有两个值,区块数和难度也是存放在区块结构中。 使用的工作量证明算法叫做 `Ethash `_ ( `the Dagger-Hashimoto algorithm `_ 的一个变种),需要找到某一个特定要求的算法输入,使得算法结果符合给定的难度。关键点在于PoW算法目前除了暴力穷举外没有别的方法可以计算得出,但同时结果的验证确非常简单,只要算法的输出结果(也就是hash函数的结果)满足我们预先设定的要求。我们可以保证通过控制难度阈值来保证找到符合结果的值的平均时间。这就保证了我们可以控制难度,来控制一个新区块的产生时间间隔。 在协议的保证下,通过动态调整的难度来保证整个网络计算力平均15秒可以产生出一个新的合法区块。我么可以说整个网络具有15秒的区块时间。这个基本的系统同步的“心跳”确保了维护一个分叉(双重花费)和历史重写是不可能实现的,除非你可以控制足够的网络计算能力(这被称为51%攻击)。 任何加入到网络的节点都可以成为矿工,他们的收益和它们的哈希计算能力成正比。计算力通过哈希率来描述,即每秒可以尝试计算哈希的次数。 Ethash PoW是内存饥饿型算法,可以有效抵御ASIC矿机,内存饥饿是通过工作量证明实现的,需要依赖块头数据和随机数固定资源的集合,这个资源(大小量级为数个GB)被称为DAG。区块链中每30000个块会生成一个完全不同的DAG,按照15秒一个块的难度,大约一个DAG数据会使用125个小时(大约5.2天)被称为一个纪元(epoch)。因为DAG数据仅依赖于块的高度,所以是可以提前被计算出来的,如果没有提前计算那么节点需要等待DAG计算完毕后,才能继续生产新的区块。请注意在验证PoW结果的时候是不需要DAG资源的,仅需要很低的CPU和内存资源。 一种特殊的情况,你的节点从头同步完节点后,挖矿需要等到当前纪元(epoch)的DAG文件生成完毕后才能开始。 挖矿回报 -------------------------------------------------------------------------------- 从工作量证明中胜出的矿工的到新区块的奖励: * 一个 *静态块* 奖励包含5.0个以太币 * 消耗掉的gas - 换算成以太币依赖于当前的gas价格 * 如果引用来叔父块,那么每引用一个叔父区块会收额外得到叔父块奖励的1/32(5Eth乘以 1/32 约等于0.156Eth) gas奖励来自于块中所有交易者提供的gas,被换算成以太币奖励给矿工。这些以太币是之前已经存在的,并不是此次挖矿产生的。 *叔父块* 也是合法的区块,被引用的叔父块也会获得奖励。奖励合法的叔父块会中和网络滞后带来的影响,增加网络的安全性(这个被称为GHOST协议Greedy Heaviest-Observed Sub-Tree)。被引用的叔父块的矿工,将会获得叔父块中5个以太币的7/8也就是4.375个以太币,每一个块最多可以引用2个叔父块。 * `ELI5 reddit上有关叔父块的提案系统讨论 `_ * `解释叔父块概念的帖子 `_ 成功挖矿取决于块难度的设置,块的难度是根据网络算力动态调整的,控制大约每12秒出一个新块。你找到合法的区块,取决于你的hash计算能力。 Ethash DAG -------------------------------------------------------------------------------- Ethash使用DAG(有向无环图)作为工作量证明的算法,每个纪元(epoch)都会生成一个DAG,一个纪元就是30000个区块(125个小时等同于5.2天)。DAG生成会需要比较长的时间,如果客户端按照需要生成它,你会发现在每一个纪元的第一个块会生成的特别慢。然而DAG的生成仅仅依赖于块的高度,所以它可以被提前计算得到,以避免纪元交接时的长时间等待。 ``geth`` 和 ``ethminer`` 的实现都会同时生成2个DAG以保证纪元平滑过渡。自动生成DAG可以通过命令行来控制开和关,默认情况下 ``geth`` 启动时如果带有参数 ``--mine`` 那么自动生成就出于打开状态。请注意客户端的DAG是共享的,如果你有多个运行的实例,请确认只有一个客户端自动生成DAG,其余的实例的DAG自动生成选项都处于关闭状态。 为特定的纪元生成DAG可以通过如下命令: .. code-block:: bash geth makedag 例如: ``geth makedag 360000 ~/.ethash`` 值得注意的是,ethash会使用如下默认位置来存放DAG文件 - ``~/.ethash`` (Mac/Linux) - ``~/AppData/Ethash`` (Windows) 如果运行了多个实例,那么多个实例可以从上述位置共享DAG信息 算法 ================================================================================ 我们的算法,`Ethash `__ (Dagger-Hashimoto算法的改进版),围绕着一个被称为DAG的巨大、瞬时、随机生成的数据块进行,并尝试在这个数据块之上解决特定的约束,也就是处于块头的一个哈希值。 被设计成可以只占用少量CPU资源就可以快速验证的哈希算法,想要得到挖矿速度的提升,只有通过提高内存的带宽和数量。巨大的内存需求量意味着,大型矿工很难得到超越线性的增长收益。巨大的内存需求量,意味着大型矿工通过提高中央处理单元的速度,同时通过共享内存获得的收益,和单独的处理器加等量巨大内存的收益相差无几。这就避免了导致出现算计中心化的问题。 外部的挖矿应用程序和以太坊的守护进程通信是通过JSON-RPC API进行的,两个RPC方法分别是: ``eth_getWork`` 和 ``eth_submitWork`` 。 相关的文档存放在这里:`JSON-RPC API `_ 和 `miner `_ 。 想要进行挖矿,你的以太坊客户端需要完全同步区块链数据,而且至少需要一个以太坊帐号,这个帐号用来接收挖矿所得的以太币。帐号相关的文档,请查看: ":ref:`creating_an_account`" 章节。 .. warning:: 请确保你的区块链同步的是主网络的区块信息,否则的话你挖出的以太币不是属于主网络的。 CPU挖矿 ================================================================================ 你可以使用你计算机的中央处理器(CPU)来开采以太币,这种方式目前已经不太适合了,因为GPU的挖矿效率已经比它高出两个数量级了。然而,你可以继续使用CPU在Morden测试网络或者你的私有链上进行挖矿,来获得你测试所需要的以太币。这样你就不用为了测试合约和交易而使用公有链上真实的以太币了。 .. note:: 测试网络中的以太币除了测试的作用外没有任何价值(查看 :ref:`test-networks`). 使用geth ------------------------------- 当你使用 ``geth`` 启动你的以太坊客户端时默认不会进行挖矿>动作,想开启CPU挖矿模式,你需要在启动时使用参数 ``--mine`` ,还有一个参数 ``-minerthreads`` ,可以用来启动多个并行的挖矿线程(默认值等于当前处理器的核心数) ``geth --mine --minerthreads=4`` 你可以使用 `命令台 `__ 在运行时开启或关闭CPU挖矿,命令为:``miner.start()`` 参数为并行的挖矿线程数。 .. code-block:: Javascript > miner.start(8) true > miner.stop() true 清注意只有与网络进行了同步那么挖矿才是有意义的(在共识块之上进行挖掘)。因此,以太坊区块链下载器/同步器会使挖矿滞后直到同步完成,完成后挖矿会自动开始,除非你使用命令 ``miner.stop()`` 取消挖矿。 为了得到以太币你必须有一个钱袋(etherbase)地址,这个地址就是你的默认账户,如果不设置钱袋地址,那么挖矿命令 ``geth --mine`` 不会启动。 你可以使用如下命令设置你的钱袋地址: .. code-block:: bash geth --etherbase 1 --mine 2>> geth.log // 1 is index: second account by creation order OR geth --etherbase '0xa4d8e9cae4d04b093aac82e6cd355b6b963fb7ff' --mine 2>> geth.log 也可以在命令台中重设你的钱袋地址: .. code-block:: javascript miner.setEtherbase(eth.accounts[2]) 请注意设置的地址不需要是你本地的地址,只要是合法的账号地址就可以。 你可以使用命令 `to add extra Data `__ (最多允许32字节)添加信息到你所挖的区块中,编码使用的是unicode,你可以设置你的标签信息。 .. code-block:: javascript miner.setExtra("ΞTHΞЯSPHΞЯΞ") ... debug.printBlock(131805) BLOCK(be465b020fdbedc4063756f0912b5a89bbb4735bd1d1df84363e05ade0195cb1): Size: 531.00 B TD: 643485290485 { NoNonce: ee48752c3a0bfe3d85339451a5f3f411c21c8170353e450985e1faab0a9ac4cc Header: [ ... Coinbase: a4d8e9cae4d04b093aac82e6cd355b6b963fb7ff Number: 131805 Extra: ΞTHΞЯSPHΞЯΞ ... } 你可以通过命令 `miner.hashrate `_ 来查看你的哈希率,结果的单位是H/s(哈希操作每秒)。 .. code-block:: javascript > miner.hashrate 712000 在你成功挖到一些区块后,你可以检查你账户中的以太币数量,现在假设你的账户是本地的: .. code-block:: javascript > eth.getBalance(eth.coinbase).toNumber(); '34698870000000' 为了可以把你赚取的以太币当作gas进行花费,你需要把账号解除锁定: .. code-block:: javascript > personal.unlockAccount(eth.coinbase) Password true 你可以检查哪些区块被指定的矿工(地址)挖出,你可以在命令行中使用如下代码片段: .. code-block:: javascript function minedBlocks(lastn, addr) { addrs = []; if (!addr) { addr = eth.coinbase } limit = eth.blockNumber - lastn for (i = eth.blockNumber; i >= limit; i--) { if (eth.getBlock(i).miner == addr) { addrs.push(i) } } return addrs } // scans the last 1000 blocks and returns the blocknumbers of blocks mined by your coinbase // (more precisely blocks the mining reward for which is sent to your coinbase). minedBlocks(1000, eth.coinbase); //[352708, 352655, 352559] 注意到,经常会发生这样的情况,我们发现了一个块,但是这个块从未变成正式的区块,这意味着本地的链中包含了你的块,此时状态显示挖矿奖励进入到你的账号中,然而,过了一会,一条更好的链被发现,我们会切换到那条不包含我们发现的区块的那条链上,在这条更好的链上并没有包含我们的块,也就意味着我们的账号中的以太币并没有记录到链上,这也就是经常可以看到账户中的资金会有一些浮动变化。 GPU挖矿 ================================================================================ 硬件 ------------------------------- (以太坊的工作量证明)算法是内存饥饿型算法,因为需要将DAG(大小量级为数个GB)数据放入到内存中,每个GPU的RAM都需要达到1-2GB(译者注:现在需要GPU的最小RAM已经大于2GB了)。如果你看到 ``Error GPU mining. GPU memory fragmentation?`` 错误,那你肯定是没有足够的内存。 GPU挖矿使用OpenCL进行实现,所以AMD的显卡会比同档次的NVIDIA显卡速度“更快”。 ASIC和FPGA的效率相对较低,所以不推荐。 获取适合你平台芯片的OpenCL可以从下面的链接获得。 - `AMD SDK openCL `_ - `NVIDIA CUDA openCL `_ Ubuntu Linux 设置过程 ------------------------- 在这个快速教程中,你需要14.04或者15.04版本的Ubuntu,显卡驱动程序使用fglrx。你也可以使用其它的平台和NVIDIA的驱动程序,但是你必须自己去安装适合他们的OpenCL,例如可以参考: `Genoil's ethminer fork `_ 。 如果你的系统是15.04版本,请通过 "Software and Updates > Additional Drivers" 找到如下设置 "Using video drivers for the AMD graphics accelerator from fglrx"。 如果你的系统是14.04版本,请通过 "Software and Updates > Additional Drivers" 找到如下设置 "Using video drivers for the AMD graphics accelerator from fglrx"。不幸的是,对于版本号为14.04.02点系统,可能会应为一个已知的BUG导致不能切换到合适的显卡驱动,而不能继续挖矿。 所以,当你什么别动操作都没做,而且遇到了这个BUG,请通过 "Software and updates > Updates" ,并将选项 "Pre-released updates trusty proposed"选中,然后返回到 "Software and Updates > Additional Drivers" ,设置 "Using video drivers for the AMD graphics accelerator from fglrx"。然后重启系统,去检查一下显卡驱动是否正确被安装(重新打开"Additional Drivers"查看)。 无论你做了什么,如果你的系统是14.04.02版本,那么久不要切换显卡驱动或者重新配置显卡驱动,比如:使用aticonfig --initail(尤其是使用了-f,--fource选项)会“改变”你的设置。如果不小心导致了变动,那么你需要重新卸载驱动、重启、安装新驱动然后再重启。 Mac 设置过程 ------------------------------- .. code-block:: bash wget http://developer.download.nvidia.com/compute/cuda/7_0/Prod/local_installers/cuda_7.0.29_mac.pkg sudo installer -pkg ~/Desktop/cuda_7.0.29_mac.pkg -target / brew update brew tap ethereum/ethereum brew reinstall cpp-ethereum --with-gpu-mining --devel --headless --build-from-source 检查你的状态: .. code-block:: bash aticonfig --adapter=0 --od-gettemperature Windows 设置过程 ------------------------------- `下载最新版本的 Eth\+\+ 安装包 `_ 并且在 "Choose Components(选择组件)" 中选中ethminer选项。 .. image:: img/eth_miner_setup.png .. :height: 513px .. :width: 399 px :alt: ethereum-ethminer-set-upfdg 通过geth启用ethminer ------------------------------- .. code-block:: bash geth account new // Set-up ethereum account if you do not have one geth --rpc --rpccorsdomain localhost 2>> geth.log & ethminer -G // -G for GPU, -M for benchmark tail -f geth.log ``ethminer`` 通过端口8545(geth的默认RPC端口)与geth进行通信,你可以通过参数 ``--rpcport`` 把一个新端口号提供给 ``geth`` ,Ethminer可以通过任何端口找到geth。你需要使用命令 ``--rpccorsdomain localhost`` 来设置CORS头。你也可以通过命令 ``-F http://127.0.0.1:3301`` 来设置ethminer的端口。如果你想要在同一台机器上运行多个矿工实例,那么手动设置端口号就很有必要了,虽然这么做没有什么意义。如果你使用的是测试网络,我们建议你使用CPU挖矿。 .. note:: 你没有必要在命令台中给 ``geth`` 提供 ``--mine`` 参数除非你想在GPU挖矿的基础上进行CPU挖矿。 如果 ``ethminer`` 的默认值不起作用,那么请通过下面的命令指定OpenCL设备: - ``--opencl-device X`` X 可以选择 {0, 1, 2,...} 当 ``ethminer`` 使用参数 ``-M`` (检测),你可以看到下面的提示信息: .. code-block:: bash Benchmarking on platform: { "platform": "NVIDIA CUDA", "device": "GeForce GTX 750 Ti", "version": "OpenCL 1.1 CUDA" } Benchmarking on platform: { "platform": "Apple", "device": "Intel(R) Xeon(R) CPU E5-1620 v2 @ 3.70GHz", "version": "OpenCL 1.2 " } 想要调试 ``geth``: .. code-block:: bash geth --rpccorsdomain "localhost" --verbosity 6 2>> geth.log 想要调试 ``ethminer``: .. code-block:: bash make -DCMAKE_BUILD_TYPE=Debug -DETHASHCL=1 -DGUI=0 gdb --args ethminer -G -M .. note:: 哈希率这个概念不适合GPU挖矿模式下的 ``geth`` 如果查看ethminer的哈希率, `` miner.hashrate``总是返回0。 通过eth启用ethminer ------------------------------- 在单GPU上进行挖矿 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 在单GPU上进行挖矿你所需要做的就是使用下面的命令启动eth: .. code-block:: bash eth -v 1 -a 0xcadb3223d4eebcaa7b40ec5722967ced01cfc8f2 --client-name "OPTIONALNAMEHERE" -x 50 -m on -G - ``-v 1`` 将信息详细程度设置为1,保证我们不会被大量的信息干扰到 - ``-a YOURWALLETADDRESS`` 设置收取挖矿回报的帐号地址,上面的例子只是一个示例,这个参数相当重要,请确保正确填写以免收不到挖矿奖励 - ``--client-name "OPTIONAL"`` 给矿工设置一个名字以方便在网络上识别它 - ``-x 50`` 设置一个较高的节点上限,方便在开始时更容易找到节点 - ``-m on`` 设置自动启动 - ``-G`` 设置GPU挖矿模式开启 当客户端运行后你可以通过 ``ethcosole `` 与之交互。 在多GPU上进行挖矿 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 使用geth进行多GPU挖矿和使用eth进行多GPU挖款是非常相似的过程。 请确保你的收款地址填写正确: .. code-block:: bash eth -v 1 -a 0xcadb3223d4eebcaa7b40ec5722967ced01cfc8f2 --client-name "OPTIONALNAMEHERE" -x 50 -j 注意到我们添加了一个参数 -j ,这可以让客户端启动JSON-RPC服务以实现和ethminer实例的通信。此外我们移除了挖矿相关的参数,因为我们即将使用ethminer为我们挖矿,请为每一块显卡启动一个不同的ethminer实例: .. code-block:: bash ethminer --no-precompute -G --opencl-device X X是匹配设备的索引号,符合要求的OpenCL设备会被按照{0,1,2,..}进行编号。为了列举出符合要求的OpenCL设备列表,你可以使用命令 ``ethminer --list-devices`` ,它将列举出所有设备和详细信息。 下面是一个输出的例子: .. code-block:: console [0] GeForce GTX 770 CL_DEVICE_TYPE: GPU CL_DEVICE_GLOBAL_MEM_SIZE: 4286345216 CL_DEVICE_MAX_MEM_ALLOC_SIZE: 1071586304 CL_DEVICE_MAX_WORK_GROUP_SIZE: 1024 最后参数 ``--no-precompute`` 允许ethminer不提前生成下一个纪元的DAG数据,当然这个是不推荐的,因为它会让你的挖矿过程在每次纪元交替时产生中断。 标准环境检测 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 计算能力随着内存带宽的增长而增长,我们的实现是用OpenCL写的,所以对AMD GPU的支持会比NVIDIA GPU的更好,有证据显示同样价格标准下,AMD GPU的挖矿效果表现要优于NVIDIA的GPU。 检测单显卡,你可以使用ethminer的-M检测模式进行: .. code-block:: bash ethminer -G -M 如果你有多个设备,需要分别对每一个设备进行检测,你可以像前面介绍的那样使用 --opencl-device 参数: .. code-block:: bash ethminer -G -M --opencl-device X 使用ethminer的 ``--list-devices`` 来列举出设备的索引号X {0,1,2,...}。 在Windows上进行挖矿,首先 `下载windows的geth执行文件 `_ 。 * 解压缩Geth(右键选择解压缩),启动cmd命令行,使用cd命令进入到geth的目录。 * 使用命令 ``geth --rpc`` 启动geth。 进行到这一步,以太坊的区块链就开始下载同步了,很有可能你的防火墙会弹出一个提示框,如果是这样的话,请点击“允许访问”。 接下来继续: * 首先 `下载和安装ethminer `_ ,C++版本的挖矿软件(防火墙可能还会提示是否允许:请点击允许) * 打开一个新的cmd命令行(前一个让它继续运行),通过cd命令切换路径到 ``cd /ProgramFiles/Ethereum(++)/release`` * 等到geth同步完成后,输入命令 ``ethminer -G`` 开始挖矿 到这里可能会出现一些问题,如果你遇到了错误提示,你可以在命令台通过 ``Ctrl+C`` 来退出。如果出现提示信息"Insufficient Memory",那就说明你的GPU没有足够的内存来支持以太币的挖掘。 矿池挖矿 ================================================================================ 矿池是一个合作体,通过整合分散矿工的算力合作开采,来使每个矿工的回报趋于平滑。作为回报,(矿池的组织者)通常会收取0-5%的挖矿回报作为手续费,矿池通过集中计算每个矿工的贡献,来将所有的挖矿收益按照贡献比例重新分配给每个矿工。 .. warning:: 大部分的矿池涉及到第三方组织,中心化的组织意味着不可信,换句话说,就是第三方矿池都存在带着你的挖矿钱“跑路”的风险,请谨慎选择,另外有一些去中心化、去信任化的开源矿池可被选择。 .. warning:: 矿池仅仅是计算工作量的一个平台,他们不验证区、也不运行以太坊虚拟机来确保交易状态的变化,这让矿池的行为在安全上很像是一个单独的节点,他们的算力增长增加了51%攻击的风险,请确保你遵循网络分发能力,不要让矿池增长到足够大。 矿池列表 -------------------------------------------------------------------- * `coinotron`_ * `nanopool`_ * `ethpool`_ - Predictable solo mining, unconventional payout scheme, affiliated with `etherchain\.org`_. * `supernova`_ * `coinmine.pl`_ * `eth.pp.ua`_ * `talkether`_ - Unconventional payout scheme, partially decentralized * `weipool`_ * `ethereumpool`_ * `pooleum`_ * `alphapool`_ * `cryptopool`_ * `unitedminers`_ * `dwarfpool`_ - Try to avoid this (currently over 50% of the network) * `laintimes `_ - Discontinued .. _Ethpool: https://github.com/etherchain-org/ethpool-core .. _Ethpool source: https://github.com/etherchain-org/ethpool-core .. _ethereumpool: https://ethereumpool.co/ .. _nanopool: http://eth.nanopool.org/ .. _pooleum: http://www.pooleum.com .. _alphapool: http://www.alphapool.xyz/ .. _dwarfpool: http://dwarfpool.com/eth .. _talkether: http://talkether.org/ .. _weipool: http://weipool.org/ .. _supernova: https://eth.suprnova.cc/ .. _coinmine.pl: https://www2.coinmine.pl/eth/ .. _eth.pp.ua: https://eth.pp.ua/ .. _coinotron: https://www.coinotron.com/ .. _etherchain.org: https://etherchain.org/ .. _unitedminers: http://eth.unitedminers.cloud/ .. _cryptopool: http://ethereum.cryptopool.online/ 挖矿相关资源 ======================================================= * `Top miners of last 24h on etherchain `_ * `pool hashrate distribution for august 2015 `_ * `Unmaintained list of pools on Forum `_ * `Mining profitability calculator on cryptocompare `_ * `Mining profitability calculator on cryptowizzard `_ * `Mining profitability calculator on etherscan `_ * `Mining profitability calculator on In The Ether `_ * `Mining difficulty chart on etherscan `_ .. _POS vs POW: 工作量证明(POW)vs 股权证明(POS) ----------------------------------- * https://www.reddit.com/r/ethereum/comments/38db1z/eli5_the_difference_between_pos_and_pow/ * https://blog.ethereum.org/2014/11/25/proof-stake-learned-love-weak-subjectivity/ * https://www.reddit.com/r/ethereum/comments/42o8oy/can_someone_explain_the_switch_to_pos_how_and_when/