Ethash挖矿场景下如何计算矿池份额(share)难度
Ethash份额难度计算正确方案
你之前计算结果错误的核心原因是接口参数传值不符合规范,且难度计算逻辑有误,具体修正方式如下:
一、接口参数取值规则
mkcache()和run()方法的入参不能直接传epoch值,需按Ethash固定规则计算对应大小:
- Ethash每30000个区块为一个epoch,每个epoch对应固定的cache大小和DAG(fullSize)大小:
- 初始cache大小为16777216字节(16MB),每个epoch递增131072字节,最终取邻近的符合规范的素数为实际
cacheSize入参 - 初始DAG大小为1073741824字节(1GB),每个epoch递增8388608字节,最终取邻近的符合规范的素数为实际
fullSize入参
- 初始cache大小为16777216字节(16MB),每个epoch递增131072字节,最终取邻近的符合规范的素数为实际
- 你给出的seedHash对应epoch为503,实际入参值为:
cacheSize = 82705027,fullSize = 5293198087。之前传入1024、1024*32、epoch值503都是错误值,会直接导致哈希计算结果完全偏离。
二、难度计算逻辑
ethash.run()返回值中,使用result.hash字段计算难度,result.mix是Ethash校验用的中间值,仅在提交份额时作为参数传给矿池,不参与难度计算。- 难度计算公式为:
难度值 = 2^256 / (result.hash转成的256位大整数值)
注意字节序问题:result.hash默认是小端序Buffer,计算前需要先翻转成大端序再转成无符号大整数,不能直接把十六进制字符串除以1e6换算单位,该计算方式完全错误。 - 最终得到的难度值单位为H,除以10^9即可得到GH单位的结果,和你看到的T-Rex上报的18.33G一致。
三、修正后的可运行代码
const Ethash = require('@ethereumjs/ethash').default; const { MemoryLevel } = require('memory-level'); const cacheDB = new MemoryLevel(); const ethash = new Ethash(cacheDB); // 从Stratum抓包数据中提取对应字段 const seed = '0x78255e703ddc0c08a70aba14dafca75ff40401240c1622d2f80b398919451e14'; const blockheader = '0xbafb9b219bb51e0b47abf28e6044322a0f181926496528bbf137eef718a6623b'; const nonce = '0x605f42c3367bd64a'; // 处理Buffer时去掉0x前缀 const seedBuffer = Buffer.from(seed.slice(2), 'hex'); const nonceBuffer = Buffer.from(nonce.slice(2), 'hex'); const blockheaderBuffer = Buffer.from(blockheader.slice(2), 'hex'); // Epoch503对应的正确参数值 const cacheSize = 82705027; const fullSize = 5293198087; ethash.mkcache(cacheSize, seedBuffer); const result = ethash.run(blockheaderBuffer, nonceBuffer, fullSize); // 小端转大端后转BigInt计算难度 const hashBigEndian = Buffer.from(result.hash).reverse(); const hashInt = BigInt('0x' + hashBigEndian.toString('hex')); const maxUint256 = 2n ** 256n; const diff = maxUint256 / hashInt; // 单位转换为GH const diffGH = Number(diff) / 10**9; console.log(`对应份额难度: ${diffGH.toFixed(2)} G`); // 可对比输出的mix值和抓包到的提交值是否一致,校验计算正确性 console.log(`计算得到Mix哈希: 0x${result.mix.toString('hex')}`);
补充说明
- 入参的nonce、区块头、seedHash直接使用Stratum协议中抓包到的十六进制值即可,不需要额外做字节序翻转,仅在最终计算难度时需要翻转result.hash的字节序。
- 矿池的有效份额不需要满足以太坊主网出块难度,只要计算得到的难度值大于等于矿池设置的最低份额难度阈值,就会被矿池认定为有效份额。
内容的提问来源于stack exchange,提问作者Feche1320
相关产品推荐
相关产品推荐

