《嵌⼊式软硬件梳理》-9.2.3、挖矿协议stratum
2.3 挖矿协议stratum
2.3.1 stratum简介
2012年底,Stratum协议是为了扩展⽀持矿池挖矿⽽编写的挖矿协议,并替换了废弃的getwork协议。挖矿服务技术最初是在Slush's
pool's⽹站被公告出来。没过多久,BTCGuild提供了可替代的“备忘单”形式的⽂档。
2.3.2 stratum挖矿过程
【01】矿机(client)使⽤subscribe⽅法连接矿池(rver)
{“id”: 1, “method”: “mining.subscribe”, “params”: []}\n //申请链接,参数可以不填
{“id”: 1, “result”: [ [ ["mining.t_difficulty", "mining.t_difficulty"], ["ify", "ify"]], “08000002″, 4], “error”: null}\n //返回数据
矿池返回的数据,需要矿⼯记录在本地,在整个挖矿过程中都要⽤到,其中:
生日快乐怎么回复别人1)mining.t_difficulty:⽤于矿池去设置矿机当前提交任务的最⼤难度值;
营私舞弊
2)ify:⽤于矿池去发送任务给矿机进⾏运算;
3)08000002:Extranonce1,⽤于构造coinba = {cionb1,Extranonce1,Extranonce2,coinb2};//拼接
4)4 :Extranonce2_size,即Extranonce2的长度,4字节。
注:Extranonce1和Extranonce2对于挖矿很重要,⽤于增加搜索空间,现在,可有8个字节的搜索空间,即nNonce+Extranonce2;Extranonce1是矿池发过来的固定值,即在本次任务中是固定的。
【02】矿机(client)使⽤authorize⽅法向矿池(rver)授权挖矿
在矿池注册⼀个账号,添加矿⼯,矿池允许每个账号任意添加矿⼯数,并取不同名字以区分。并且每个账号对应⼀个钱包地址,⽤于矿池(rver)分配收益。女士英语
{“id”: 2,“params”: ["ur_name", "password"], “method”: “mining.authorize”}\n
{“error”: null, “id”: 2, “result”: true}\n
后勤工作计划
注:有些矿池不⽤注册账号也能挖矿,⽐如(F2Pool),那么在授权时,ur_name直接替换成钱包地址,password可以不填写。细
⼼的朋友可能发现,为什么"id"号会发⽣变化,其实这个ID号是⽤于【矿机】区别来⾃【矿池】的应答消息的,因为【矿池】的应答消息结
构有些很相似,那么【矿机】如何区别这些消息是对应哪个发送消息的应答。例如【矿池】返回两个消息应答,⼀个应答消息中的result为
true,另⼀个应答消息中的result为fal,且两个应答消息的结构⼀致,那么【矿机】接收到这两个应答后如何区别是哪个发送消息的应
答,那么这个ID号就是来⼲这件事情的。然⽽,如何消息是【矿池】主动发给【矿机】的,⽐如mining.t_difficulty和ify两
个⽅法,他们的ID号为NULL。
【03】矿池(rver)使⽤notify⽅法分配任务给矿机(client)
{“params”: ["bf", "4d16b6f85af6e2198f44ae2a6de67f78487ae5611b77c6c0440b921e00000000",
"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff20020862062f503253482f04b8864e5008",千张皮怎么做好吃
"072f736c7573682f000000000100f2052a010*********a914d23fcdf86f7e756a64a7a9688ef9903327048ed988ac00000000", ["76cffd68bba7ea661512b68ec64
“00000002″, “1c2ac4af”, “504e86b9″, fal], “id”: null, “method”: “ify”}
以上每个字段信息都是必不可少,其中:
1)bf: 任务号ID,每⼀次任务都有唯⼀的标识符。
2)4d16b6f85af6e2198f44ae2a6de67f78487ae5611b77c6c0440b921e00000000:前⼀个区块的HASH值。
3)ffffffff20020862062f503253482f04b8864e5008: coinb1,构造coinba的⾸部分数据。
4)756a64a7a9688ef9903327048ed988ac00000000: coinb2,构造coinba的尾部分数据。
5)["87820cbd02016","b2ffef2016"]: merkle_branch,交易列表。
6)00000002:区块版本号,nVersion。
7)1c2ac4af: 区块当前难度nBits,这个难度是全⽹总难度。
8)504e86b9: 当前时间戳,nTime。
9)fal:【Clean Jobs(清除⼯作标志)】;如果这个变量为true,矿⼯应该退出当前⼯作,⽴即开始新的⼯作;如果为Fal,矿⼯仍然可以继续当前的挖矿⼯作,但是应该在当前nonce范围结束后开始⼀个新的⼯作。
注:有了这个信息,再加上之前得到的Extranonce1和Extranonce2_size,就可以计算挖矿了。
【04】矿机(client)开始挖矿
1)构造coinba信息
为什么要构造coinba信息,是因为矿机需要扩展随机数,Extranonce2,来构造属于矿机⾃⼰的merkleroot,请看下图:
其中红⾊的点即为coinba(256bits),构造它是为了与其它交易列表进⾏HASH运算,⿊⾊的点为矿池分配任务中的交易列表,并与coinba进⾏hash得到最终merkleroot。
吃午餐的英文
构造coinba = {coinb1 , Extranonce1 , Extranonce2 , coinb2};//拼接
注:为啥可以这样,因为矿池帮矿⼯做了很多⼯作,矿池已经构建了coinba交易,系列化后在指定位置分割成coinb1和
coinb2,coinb1和coinb2包含指定信息,⽐如coinb1包含区块⾼度,coinb2包含了矿⼯的收益地址和
连词成句收益额等信息,但是这些信息对于矿⼯来说⽆关紧要,矿⼯挖矿的地⽅只是Extranonce2的4个字节。另外Extranonce1是矿池写⼊区块的指定信息,⼀般来说,每个矿池会写⼊⾃⼰矿池的信息,⽐如矿池名字或者域名,根据这个信息统计每个矿池的全⽹的算⼒⽐重。
2)构建merkleroot
利⽤coinba和merkle_branch两两配对成512bit,如果coinba与merkle_branch数量之和不是偶数,那么最后⼀个
merkle_branch与它⾃⾝进⾏合并得到512bits,然后把配对完成后的512bits的各个块进⾏SHA-256(SHA-256())运算,得到上⼀层的结果,然后重复上⾯的过程,继续配对计算,最终得到merkle root(256bits)。
3)构建区块头
填充余下的5个字段,现在,矿池可以在nNonce和Extranonce2⾥搜索进⾏挖矿,如果嫌搜索空间还不够,只要增加
Extranonce2_size为多⼏个字节就可以轻⽽易举的解决。
【05】矿机(client)使⽤submit⽅法向矿池(rver)提交⼯作量
当矿⼯找到⼀个符合难度的shares时,提交给矿池,提交信息量很少,都是必不可少的字段:
{“params”: ["ur_name", "bf", "00000001", "504e86ed", "b2957c02"], “id”: 3, “method”: “mining.submit”}
{“error”: null, “id”: ,3, “result”: true}
1)00000001: Etranonce2的值。
李姓名人2)504e86ed :nTime的值。
3)b2957c02 :nNonce的值。
注:矿池拿到以上5个字段后,⾸先根据任务号ID找出之前分配任务前存储的信息,然后重构区块,再验证shares难度,对于符合难度要求的shares,在检测是否符合全⽹难度。
【06】矿池(rver)使⽤t_diffculty⽅法给矿机(client)调整难度值
矿池记录每个矿⼯的难度,并根据shares率不断调节以指定适合难度。格式如下:
{ “id”: null, “method”: “mining.t_difficulty”, “params”: [32768]}
如上,其中,params[32768]便是新难度值,这个难度值是什么意思呢,以上这条信息是F2pool矿池⽐特币发给矿机的难度(时间2018/07/09),这个数字的意思是派给矿机的任务难度是1个单位⽐特币难度值的32768倍,⼀个单位的⽐特币难度值是对少呢,答案是:0x1d00ffff,转化为256bits是0x00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff;转化过程使⽤⼀个公式:data = (0x1d00ffff & 0x00ffffff) * 256**(0x1d - 3);其中**是指数操作;那么32768倍的⽐特币难度单位的值是多少呢,答案是:(0x00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff)/32768。
上述挖矿算法我已⽤C++写出来,由于我的电脑的算⼒太低,⽆法提交矿池发给我的任务难度,因此最后⼀个提交过程⽆法验证成功,测试提交,矿池会返回fal。矿池从联机发第⼀个任务后,如果3秒内,矿机没有提交结果,矿池会再发⼀个任务,连续发送三个任务都没有提交的,则矿池认为矿机断开连接,需要重新连接。