比特币挖矿

版权声明:本文为博主原创文章,转载请注明来源!获取更新内容请关注我的开源项目:https://github.com/zcc0721/MasterBlockchain https://blog.csdn.net/u013137970/article/details/68961122

挖矿收益

比特币挖矿收益每210000个区块减少一半,即第0到209999号区块挖矿收益为50BTC。第210000到419999号区块挖矿收益为25BTC。整个减半周期大约4年。

比特币历次减半时间

区块号 减半后收益 时间(格林尼治时间)
210000 25BTC 2012-11-28 15:24:38
420000 12.5BTC 2016-07-09 16:46:13

减半64次后,大约到2140年后,所有矿工收益将由交易费构成。至此,所有的2,099,999,997,690,000聪比特币(约2100万BTC)将全部发行完毕。我们可以使用一个简单的Python程序计算出总的比特币数量:

# 210000 is around every 4 years with a 10 minute block interval
reward_interval = 210000
# 50 BTC = 50 0000 0000 Satoshis
current_reward = 50 * 10**8
total = 0
count = 0
while current_reward > 0:
    total += reward_interval * current_reward
    current_reward /= 2
    count += 1
    print "count is :", count, "; current_reward is :", current_reward
print "Total BTC to ever be created:", total, "Satoshis"

运行结果:

count is : 1 ; current_reward is : 2500000000
count is : 2 ; current_reward is : 1250000000
count is : 3 ; current_reward is : 625000000
count is : 4 ; current_reward is : 312500000
count is : 5 ; current_reward is : 156250000
count is : 6 ; current_reward is : 78125000
count is : 7 ; current_reward is : 39062500
count is : 8 ; current_reward is : 19531250
count is : 9 ; current_reward is : 9765625
count is : 10 ; current_reward is : 4882812
count is : 11 ; current_reward is : 2441406
count is : 12 ; current_reward is : 1220703
count is : 13 ; current_reward is : 610351
count is : 14 ; current_reward is : 305175
count is : 15 ; current_reward is : 152587
count is : 16 ; current_reward is : 76293
count is : 17 ; current_reward is : 38146
count is : 18 ; current_reward is : 19073
count is : 19 ; current_reward is : 9536
count is : 20 ; current_reward is : 4768
count is : 21 ; current_reward is : 2384
count is : 22 ; current_reward is : 1192
count is : 23 ; current_reward is : 596
count is : 24 ; current_reward is : 298
count is : 25 ; current_reward is : 149
count is : 26 ; current_reward is : 74
count is : 27 ; current_reward is : 37
count is : 28 ; current_reward is : 18
count is : 29 ; current_reward is : 9
count is : 30 ; current_reward is : 4
count is : 31 ; current_reward is : 2
count is : 32 ; current_reward is : 1
count is : 33 ; current_reward is : 0
Total BTC to ever be created: 2099999997690000 Satoshis

我们发现,经过33次减半后,即区块高度为6930000,矿工的收益将降为0聪。比特币开发者参考中也规定区块高度小于6930000的时候矿工有权获得挖矿补贴1。而实际上,我们在比特币源代码的bitcoin/src/validation.cpp文件中可以发现采用向右移位64次达到相同目的:

CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams)
{
    int halvings = nHeight / consensusParams.nSubsidyHalvingInterval;
    // Force block reward to zero when right shift is undefined.
    if (halvings >= 64)
        return 0;

    CAmount nSubsidy = 50 * COIN;
    // Subsidy is cut in half every 210,000 blocks which will occur approximately every 4 years.
    nSubsidy >>= halvings;
    return nSubsidy;
}

说明

  • 矿工的区块奖励(block reward)包含两部分:交易费用(transaction fees)和区块补贴(block subsidy)。矿工一直能够获得交易费用,只要用户愿意给。但是挖矿补贴却只有在区块高度小于6930000的时候才能获得,之后只有交易费用。

整合交易至区块

矿工收到新的区块后,将自己内存池中已经在新的区块被验证整合的交易移除,确保留在内存池的交易都是未确认的。

交易优先级

交易的优先级由以下因素决定:

  • 交易输入值
  • UTXO的块龄:自该UTXO被记录到区块链为止所经历过的区块数,即这个UTXO在区块链中的深度。
  • 交易的总长度

计算公式为:

priority = sumvalue of input * input age)/ transaction size

挖矿难度

比特币的挖矿难度可以使用Target Threshold,nBits或Difficulty表示,它们互相等价:

  • Target Threshold是一个256位的无符号整型数。
  • nBits是Target Threshold保存在区块头中采用特殊编码方式的值。
  • Difficulty是当前的区块挖矿难度与标准难度之间的比。标准难度有两种,一种叫做pool difficulty(或pdiff),这个值的被除数是前32位为0,接下来的224位全为1,表示为十六进制值为0x00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF。还有一种储存在区块头中的格式,叫做bdiff。因为区块头中表示挖矿难度的字段只有4个字节的存储空间,因此我们必须要牺牲一点精度,需要采用一种特殊的浮点数表示。bdiff的被除数值是前32位为0,接下来的16位为1,最后的208位全为0,表示为十六进制值为0x00000000FFFF0000000000000000000000000000000000000000000000000000

这三个值的转化关系可以采用下面的实例来说明:

首先获取哈希值为000000000003ba27aa200b1cecaad478d2b00432346c3f1f3986da1afd33e506的区块原生十六进制信息如下:

0100000050120119172a610421a6c3011dd330d9df07b63616c2cc1f1cd00200000000006657a9252aacd5c0b2940996ecff952228c3067cc38d4885efb5a4ac4247e9f337221b4d4c86041b0f2b57100401000000010000000000000000000000000000000000000000000000000000000000000000ffffffff08044c86041b020602ffffffff0100f2052a010000004341041b0e8c2567c12536aa13357b79a073dc4444acb83c4ec7a0e2f99dd7457516c5817242da796924ca4e99947d087fedf9ce467cb9f7c6287078f801df276fdf84ac000000000100000001032e38e9c0a84c6046d687d10556dcacc41d275ec55fc00779ac88fdf357a187000000008c493046022100c352d3dd993a981beba4a63ad15c209275ca9470abfcd57da93b58e4eb5dce82022100840792bc1f456062819f15d33ee7055cf7b5ee1af1ebcc6028d9cdb1c3af7748014104f46db5e9d61a9dc27b8d64ad23e7383a4e6ca164593c2527c038c0857eb67ee8e825dca65046b82c9331586c82e0fd1f633f25f87c161bc6f8a630121df2b3d3ffffffff0200e32321000000001976a914c398efa9c392ba6013c5e04ee729755ef7f58b3288ac000fe208010000001976a914948c765a6914d43f2a7ac177da2c2f6b52de3d7c88ac000000000100000001c33ebff2a709f13d9f9a7569ab16a32786af7d7e2de09265e41c61d078294ecf010000008a4730440220032d30df5ee6f57fa46cddb5eb8d0d9fe8de6b342d27942ae90a3231e0ba333e02203deee8060fdc70230a7f5b4ad7d7bc3e628cbe219a886b84269eaeb81e26b4fe014104ae31c31bf91278d99b8377a35bbce5b27d9fff15456839e919453fc7b3f721f0ba403ff96c9deeb680e5fd341c0fc3a7b90da4631ee39560639db462e9cb850fffffffff0240420f00000000001976a914b0dcbf97eabf4404e31d952477ce822dadbe7e1088acc060d211000000001976a9146b1281eec25ab4e1e0793ff4e08ab1abb3409cd988ac0000000001000000010b6072b386d4a773235237f64c1126ac3b240c84b917a3909ba1c43ded5f51f4000000008c493046022100bb1ad26df930a51cce110cf44f7a48c3c561fd977500b1ae5d6b6fd13d0b3f4a022100c5b42951acedff14abba2736fd574bdb465f3e6f8da12e2c5303954aca7f78f3014104a7135bfe824c97ecc01ec7d7e336185c81e2aa2c41ab175407c09484ce9694b44953fcb751206564a9c24dd094d42fdbfdd5aad3e063ce6af4cfaaea4ea14fbbffffffff0140420f00000000001976a91439aa3d569e06a1d7926dc4be1193c99bf2eb9ee088ac00000000

区块中nBits采用小端格式表示,解析区块信息,得到nBits字段值为0x4c86041b。因此转化为大端格式为0x1B04864C,这个值是Target Threshold的压缩格式表示,可以将它转化成256位的Target Threshold值:

开头的一个字节为指数,后面三个字节为系数,则:

Target Threshold = 0x04864C * 256 ^ (0x1B - 3) = 0x000000000004864c000000000000000000000000000000000000000000000000

计算出Target Threshold值为0x000000000004864c000000000000000000000000000000000000000000000000

再计算Difficulty的值,它有两个值,计算公式分别为:

bdiff = 0x00000000FFFF0000000000000000000000000000000000000000000000000000 / Target Threshold
pdiff = 0x00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF / Target Threshold

由此可以使用Python计算出bdiff的值:

>>> a =  0x00000000FFFF0000000000000000000000000000000000000000000000000000
>>> b =  0x000000000004864c000000000000000000000000000000000000000000000000
>>> print(a/b)
14484.162361225399

因此,得到在比特币客户端中的difficulty值bdiff为14484.162361225399。

为了检验上述结果,可以在比特币核心客户端中使用getblock "000000000003ba27aa200b1cecaad478d2b00432346c3f1f3986da1afd33e506"命令得到该区块的json格式信息:

{
  "hash": "000000000003ba27aa200b1cecaad478d2b00432346c3f1f3986da1afd33e506",
  "confirmations": 360175,
  "strippedsize": 957,
  "size": 957,
  "weight": 3828,
  "height": 100000,
  "version": 1,
  "versionHex": "00000001",
  "merkleroot": "f3e94742aca4b5ef85488dc37c06c3282295ffec960994b2c0d5ac2a25a95766",
  "tx": [
    "8c14f0db3df150123e6f3dbbf30f8b955a8249b62ac1d1ff16284aefa3d06d87", 
    "fff2525b8931402dd09222c50775608f75787bd2b87e56995a7bdd30f79702c4", 
    "6359f0868171b1d194cbee1af2f16ea598ae8fad666d9b012c8ed2b79a236ec4", 
    "e9a66845e05d5abc0ad04ec80f774a7e585c6e8db975962d069a522137b80c1d"
  ],
  "time": 1293623863,
  "mediantime": 1293622620,
  "nonce": 274148111,
  "bits": "1b04864c",
  "difficulty": 14484.1623612254,
  "chainwork": "0000000000000000000000000000000000000000000000000644cb7f5234089e",
  "previousblockhash": "000000000002d01c1fccc21636b607dfd930d31d01c3a62104612a1719011250",
  "nextblockhash": "00000000000080b66c911bd5ba14a74260057311eaeb1982802f7010f1a9f090"
}

最终,可以发现该区块的bits和difficulty字段信息与上面分析计算的相关结果一致。

nBits的大端格式表示法中,其系数最大为0x7fffff,这是因为Target Threshold数据类型是无符号整型,而它继承自有符号数据类,则在实际中Target Threshold系数的最高位有可能是1,这可能会被解析成一个负数。则在挖矿过程中难度值永远无法小于一个负数。因此,为了解决这个问题,比特币核心在生成nBits值时需要首先检查一下生成的nBits是否会被解析为一个负数。如果是,首先在系数开头补8位0,即除以256,然后指数再加上1。这样由nBits转化为Target Threshold过程中转化公式就与普通值相同了,即指数位都是减去3,转化过程上面已经提到。

举个例子说明:

哈希值为00000000d1145790a8694403d4063f323d499e655c83426834d4ce2f8dd4a2ee的区块信息如下:

{
  "hash": "00000000d1145790a8694403d4063f323d499e655c83426834d4ce2f8dd4a2ee",
  "confirmations": 459998,
  "strippedsize": 490,
  "size": 490,
  "weight": 1960,
  "height": 170,
  "version": 1,
  "versionHex": "00000001",
  "merkleroot": "7dac2c5666815c17a3b36427de37bb9d2e2c5ccec3f8633eb91a4205cb4c10ff",
  "tx": [
    "b1fea52486ce0c62bb442b530a3f0132b826c74e473d1f2c220bfa78111c5082", 
    "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16"
  ],
  "time": 1231731025,
  "mediantime": 1231716245,
  "nonce": 1889418792,
  "bits": "1d00ffff",
  "difficulty": 1,
  "chainwork": "000000000000000000000000000000000000000000000000000000ab00ab00ab",
  "previousblockhash": "000000002a22cfee1f2c846adbd12b3e183d4f97683f85dad08a79780a84bd55",
  "nextblockhash": "00000000c9ec538cab7f38ef9c67a95742f56ab07b0a37c5be6b02808dbfb4e0"
}

发现bdiff值为1,则利用bdiff与Target Threshold关系可以计算出:

Target Threshold = 0x00000000FFFF0000000000000000000000000000000000000000000000000000 / bdiff = 0x00000000FFFF0000000000000000000000000000000000000000000000000000

将Target Threshold值0x00000000FFFF0000000000000000000000000000000000000000000000000000转化为nBits的过程中可以发现其系数为0xffff00,指数为0x1c,这样:

0x00000000FFFF0000000000000000000000000000000000000000000000000000 = 0xffff00 * 256 ^ (0x1c -3)

然而由于系数最高位为1,则如果这样表示的话就可能将Target Threshold解析为负数。因此,我们将系数除以256,指数加上1,得到系数为0x00ffff,指数为0x1d。这样:

0x00000000FFFF0000000000000000000000000000000000000000000000000000 = 0x00ffff * 256 ^ (0x1d -3)

最终,nBits值为0x1d00ffff(大端表示),与json格式信息一致。

难度调整

比特币核心具体实现上存在一个差一错误2

参考资料

  • Target nBits:比特币开发者参考中对Target Threshold和nBits转化关系的描述。
  • Difficulty:比特币wiki中对difficulty的描述。

  1. Serialized Blocks
  2. Proof Of Work:比特币开发者指南对工作量证明基本原理的描述。

没有更多推荐了,返回首页