# 《区块链开发指南》一一1.3　挖矿、矿池

### 1.3　挖矿、矿池

1.3.1　挖矿原理与区块的产生

Nonce随机数通常都不会相同，但是它以严格的线性方式在增长，从0开始，每次执行散列时都会增长，当Nonce溢出时（此事经常发生），挖矿交易的extraNonce项就会增长，其将改变Merkle树的根节点。

>>> import hashlib
"81cd02ab7e569e8bcd9317e2fe99f2de44d49ab2b8851ba4a308000000000000" +
"e320b6c2fffc8d750423db8b1eb942ae710e951ed797f7affc8892b0f1fc122b" +
"c7f5d74d" +
"f2b9441a" +
"42a14695")
>>> hash.encode('hex_codec')
'1dbd981fe6985776b644b173a4d0385ddc1aa2a829688d1e0000000000000000'
>>> hash[::-1].encode('hex_codec')


1.3.2　挖矿难度

difficulty = difficulty_1_target/current_target

0x0404cb×28×(0x1b - 3) = 0x00000000000404CB000000000000000000000
???　　000000000000000000000000000


0x00000000FFFF0000000000000000000000000000000000000000000000000000/
0x00000000000404CB000000000000000000000000000000000000000000000000
= 16307.420938523983 (bdiff)


0x00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF/
0x00000000000404CB000000000000000000000000000000000000000000000000
= 16307.669773817162 (pdiff)


00000000000000000000000则是比特币网络使用的浮点编码类型，后面的位数被缩短了。

#include <iostream>
#include <cmath>
inline float fast_log(float val)
{
int * const exp_ptr = reinterpret_cast <int *>(&val);
int x = *exp_ptr;
const int log_2 = ((x >> 23) & 255) - 128;
x &= ~(255 << 23);
x += 127 << 23;
*exp_ptr = x;

val = ((-1.0f/3) * val + 2) * val - 2.0f/3;
return ((val + log_2) * 0.69314718f);
}

float difficulty(unsigned int bits)
{
static double max_body = fast_log(0x00ffff), scaland = fast_log(256);
return exp(max_body - fast_log(bits & 0x00ffffff) + scaland * (0x1d - ((bits & 0xff000000) >> 24)));
}

int main()
{
std::cout << difficulty(0x1b0404cb) << std::endl;
return 0;
}


import decimal, math
l = math.log
e = math.e
print 0x00ffff * 2**(8*(0x1d - 3)) / float(0x0404cb * 2**(8*(0x1b - 3)))
print l(0x00ffff * 2**(8*(0x1d - 3)) / float(0x0404cb * 2**(8*(0x1b - 3))))
print l(0x00ffff * 2**(8*(0x1d - 3))) - l(0x0404cb * 2**(8*(0x1b - 3)))
print l(0x00ffff) + l(2**(8*(0x1d - 3))) - l(0x0404cb) - l(2**(8*(0x1b - 3)))
print l(0x00ffff) + (8*(0x1d - 3))*l(2) - l(0x0404cb) - (8*(0x1b - 3))*l(2)
print l(0x00ffff / float(0x0404cb)) + (8*(0x1d - 3))*l(2) - (8*(0x1b - 3))*l(2)
print l(0x00ffff / float(0x0404cb)) + (0x1d - 0x1b)*l(2**8)


0xffff×2208

(0xffff×2208)/D

D×2256/(0xffff×2208)

D×248/0xffff

D×248/0xffff/600

D×232/600

5?006?860?589×232/600≈35.840 PHash/s

\$ python -c "print 20000 * 232 / 109 / 60 / 60.0"
23.85

1.3.3　矿池原理与商业模式

Slush方式：Slush矿池基于积分制，较老的shares将比新的shares拥有更低的权重，以减少一轮中切换矿池的投机分子。
Pay-Per-Share方式：该方式为立即为每一个share支付报酬。该支出来源于矿池现有的比特币资金，因此可以立即取现，而不用等待区块生成完毕或确认之后。这样可以避免矿池运营者幕后操纵。这种方法减少了矿工的风险，但将风险转移给了矿池的运营者。运营者可以收取手续费来弥补这些风险可能造成的损失。
Luke-Jr方式：该方式借用了其他方式的长处，如Slush方式一样，矿工需要提供工作证明来获得shares，如Puddinpop方式一样，当区块生成时马上进行支付。但是不像之前的方式，一个区块的shares，会被再次利用来生成下一个区块。为了区分参与矿工的交易传输费用，只有当矿工的余额超过1BTC时才进行支付。如果没有达到1BTC，那么将在下一个区块生成时进行累计。如果矿工在一周内没有提供一个share，那么矿池会将剩下的余额进行支付，不管余额是多少。
Triplemining方式：该方式是将一些中等大小矿池的计算力合并起来，然后将获得奖励的1%按照各个矿池计算力的比例分发给矿池运营者。
P2Pool方式：P2Pool的挖矿节点工作在类似于比特币区块链的一种shares链上。由于没有中心，所以也不会受到DoS攻击。和其他现有的矿池技术都不一样，在该方式下，每个节点工作的区块，都包括支付给前期shares的所有者及该节点自己的比特币。99%的奖励（50BTC +交易费用）会平均分配给矿工，另外0.5%会奖励给生成区块的人。
Puddinpop方式：一种使用“元哈希”技术的方式，使用特定的Puddinpop挖矿软件，现在已经没有矿池使用这种方式了。

+ 订阅