You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
365 lines
10 KiB
365 lines
10 KiB
------------------------------------------------------------------------- |
|
NiceHash presents |
|
========================================================================= |
|
Ethereum stratum mining protocol v1.0.0 |
|
========================================================================= |
|
revision of this document: R2 |
|
|
|
I. Introduction |
|
II. Concept |
|
III. Specifications (RFC) |
|
IV. Real world scenario |
|
V. Planned improvements |
|
VI. Contact |
|
|
|
|
|
I. Introduction |
|
--------------- |
|
|
|
Ethereum does not have official stratum protocol. It supports only |
|
GetWork, which is very resource hoggy as miners need to constantly |
|
poll pool to obtain possible new work. GetWork thus affects performance |
|
of miners and pools. Due to demand for more professional Ethereum |
|
mining, several versions of "stratum" for Ethereum emerged. These |
|
"stratums" utilize GetWork on server side (pool side) to obtain work, |
|
which would be fine, if careful considerations and precautions were |
|
taken when creating such protocols. But this was not done. Issues of |
|
these protocols are following: |
|
|
|
1. No unique data per miner/worker. Extranonce is ignored (but still |
|
sent). Each miner gets seedhash (which is always the same for every |
|
30k blocks) and headerhash (which changes every block). Then miner uses |
|
these two values and own nonces to generate hashes. Miners may be |
|
doing duplicate work (if they choose same nonces). |
|
|
|
2. Difficulty redundancy. Difficulty is sent in mining.notify message |
|
as a third parameter named target. This is not needed, because miners |
|
can calculate target hash on their own out of provided difficulty. |
|
|
|
3. Overall data redundancy. There are several fields that are not needed |
|
to be sent over network. Firstly; if extranonce is not used, it does not |
|
have to be sent. Secondly; seedhash changes every 30k blocks - there is |
|
no need to send it with every mining.notify. Thirdly; as already pointed |
|
out in 2 - target in mining.notify is redundant as set_difficulty is |
|
being used. Fourthly; mining.submit actually only needs to send nonce. |
|
Pool needs to verify nonce for validity and will calculate hash and |
|
mixhash. Bandwidth usage can be easily reduced by 50% or more if removing |
|
all mentioned redundancies. |
|
|
|
4. There are some inconsistencies compared to original slush's stratum |
|
specifications. One of them are ids. Ids should increase so that the pool |
|
can keep track of data being received. Another thing are HEX marks '0x' |
|
starting with each string field. This is, again, redundant and we will |
|
save some bandwidth if not using them. |
|
|
|
5. No specifications, only projects with implemented solutions. This |
|
usually lead to several similar versions of protocol; exactly what |
|
happened. |
|
|
|
Our goal is to make a solid, non-redundant, bullet-proof stratum mining |
|
protocol for Ethereum that does not have issues pointed out above. |
|
|
|
|
|
II. Concept |
|
----------- |
|
|
|
Ethereum's GetWork gives us 3 values: |
|
|
|
{ ... "result":[ |
|
"0x645cf20198c2f3861e947d4f67e3ab63b7b2e24dcc9095bd9123e7b33371f6cc", |
|
"0xabad8f99f3918bf903c6a909d9bbc0fdfa5a2f4b9cb1196175ec825c6610126c", |
|
"0x0000000394427b08175efa9a9eb59b9123e2969bf19bf272b20787ed022fbe6c" |
|
]} |
|
|
|
First value is headerhash, second value is seedhash and third value is |
|
target. Seedhash is used to identify DAG file, headerhash and 64 bit |
|
nonce value chosen by our miner give us hash, which, if below provided |
|
target, yield block/share. |
|
|
|
Since nonce is 64 bit (8 bytes) wide and considering very bad possible |
|
scenario, that Ethereum does not find a block in 5 minutes time, 8 bytes |
|
of nonce can support miner with speed of up to: |
|
|
|
(2^64 / 300) / 1G ~ 61,489,147 GH/s |
|
|
|
This is a very big number so we can easily consider taking some bytes off |
|
for our stratum protocol. |
|
|
|
--------------------------------------- |
|
| Bytes | Max supported hashing speed | |
|
| 8 | ~61,489,147.000 GH/s | |
|
| 7 | ~240,192.000 GH/s | |
|
| 6 | ~938.000 GH/s | |
|
| 5 | ~3.665 GH/s | |
|
| 4 | ~0.014 GH/s | |
|
--------------------------------------- |
|
|
|
Having only 4 bytes for nonce is not an option, since we already have |
|
miners capable of reaching 14 MH/s and more. Nonce width of 5 bytes |
|
allows max speed of 3.665 GH/s which shall be enough for quite some time, |
|
even if ASICs arrive. |
|
|
|
The miner needs to get seedhash, headerhash, difficulty and part of |
|
nonce (called extranonce) from pool. Miner chooses on it's own second |
|
part of the nonce (called minernonce). Extranonce glued with minernonce |
|
gives us 64 bit Ethereum nonce. |
|
|
|
|
|
III. Specifications (RFC) |
|
------------------------- |
|
|
|
Handshake happens after TCP connection is established from miner to the |
|
pool. Miner sends data first: |
|
|
|
{ |
|
"id": 1, |
|
"method": "mining.subscribe", |
|
"params": [ |
|
"MinerName/1.0.0", "EthereumStratum/1.0.0" |
|
] |
|
}\n |
|
|
|
First parameter is miner name and version (as with standard stratum |
|
protocol). Second parameter must be "EthereumStratum/Version" where |
|
Version is version of EthereumStratum miner is using according to this |
|
document's version. If pool does not support this version, it may |
|
terminate the connection or respond back with error. |
|
|
|
Note that miner iterates ids and can start with any number. Each message |
|
from miner to the pool needs to have unique id for miner to properly read |
|
responses as pool may not process miner's messages in FIFO manner. |
|
|
|
Server replies back: |
|
|
|
{ |
|
"id": 1, |
|
"result": [ |
|
[ |
|
"mining.notify", |
|
"ae6812eb4cd7735a302a8a9dd95cf71f", |
|
"EthereumStratum/1.0.0" |
|
], |
|
"080c" |
|
], |
|
"error": null |
|
}\n |
|
|
|
Response is almost the same as with standard stratum protocol with |
|
following differences; Third parameter of first parameter of result array |
|
is "EthereumStratum/Version"; If pool does not report this parameter or |
|
version is different than supported by miner, miner can expect |
|
compatibility issues and should terminate connection. Second parameter |
|
of result array is extranonce (in HEX) set by pool. There is no third |
|
parameter, because there is no extranonce2 (as with standard stratum). |
|
Extranonce may be max 3 bytes in size. |
|
|
|
Miner shall authorize during initial handshake; this is done the same way |
|
as in standard stratum protocol and will not be explained here in |
|
details. |
|
|
|
Before first job (work) is provided, pool MUST set difficulty by sending: |
|
|
|
{ |
|
"id": null, |
|
"method": "mining.set_difficulty", |
|
"params": [ |
|
0.5 |
|
] |
|
}\n |
|
|
|
First item of params array is difficulty in double data type. Conversion |
|
between difficulty and target is done the same way as with Bitcoin; |
|
difficulty of 1 is transformed to target being in HEX: |
|
00000000ffff0000000000000000000000000000000000000000000000000000 |
|
|
|
If pool does not set difficulty before first job, then miner can assume |
|
difficulty 1 was being set. |
|
|
|
When difficulty is changed, miner starts using new difficulty for every |
|
NEXT job that arrives. |
|
|
|
If miner has subscribed to extranonce notifications (detailed explanations |
|
is here: https://www.nicehash.com/?p=software#devs), then pool may change |
|
miner's extranonce by sending: |
|
|
|
{ |
|
"id": null, |
|
"method": "mining.set_extranonce", |
|
"params": [ |
|
"af4c" |
|
] |
|
}\n |
|
|
|
New extranonce is valid for all NEXT jobs sent by the pool. |
|
|
|
Pool informs miners about job (work) by sending: |
|
|
|
{ |
|
"id": null, |
|
"method": "mining.notify", |
|
"params": [ |
|
"bf0488aa", |
|
"abad8f99f3918bf903c6a909d9bbc0fdfa5a2f4b9cb1196175ec825c6610126c", |
|
"645cf20198c2f3861e947d4f67e3ab63b7b2e24dcc9095bd9123e7b33371f6cc", |
|
true |
|
] |
|
}\n |
|
|
|
First parameter of params array is job ID (must be HEX number of any |
|
size). Second parameter is seedhash. Seedhash is sent with every job to |
|
support possible multipools, which may switch between coins quickly. |
|
Third parameter is headerhash. Last parameter is boolean cleanjobs. |
|
If set to true, then miner needs to clear queue of jobs and immediatelly |
|
start working on new provided job, because all old jobs shares will |
|
result with stale share error. |
|
|
|
Miner uses seedhash to identify DAG, then tries to find share below |
|
target (which is created out of provided difficulty) with headerhash, |
|
extranonce and own minernonce. |
|
|
|
When share below target is found, miner submits it to the pool: |
|
|
|
{ |
|
"id": 244, |
|
"method": "mining.submit", |
|
"params": [ |
|
"username", |
|
"bf0488aa", |
|
"6a909d9bbc0f" |
|
] |
|
}\n |
|
|
|
Second parameter of params array is job ID, third parameter is |
|
minernonce. Note in above example that minernonce is 6 bytes, because |
|
provided extranonce was 2 bytes. If pool provides 3 bytes extranonce, |
|
then minernonce must be 5 bytes. |
|
|
|
For every work submit, pool needs to respond back with standard stratum |
|
response: |
|
|
|
{ |
|
"id": 244, |
|
"result": true, |
|
"error": null |
|
}\n |
|
|
|
Or if share was not accepted (standard stratum response): |
|
|
|
{ |
|
"id": 244, |
|
"result": false, |
|
"error": [ |
|
-1, |
|
"Job not found", |
|
NULL |
|
] |
|
}\n |
|
|
|
|
|
IV. Real world scenario |
|
----------------------- |
|
|
|
Miner connects to the pool and sends: |
|
{ |
|
"id": 1, |
|
"method": "mining.subscribe", |
|
"params": [ |
|
"EthereumMiner/1.0.0", "EthereumStratum/1.0.0" |
|
] |
|
}\n |
|
|
|
Pool responds: |
|
{ |
|
"id": 1, |
|
"result": [ |
|
[ |
|
"mining.notify", |
|
"ae6812eb4cd7735a302a8a9dd95cf71f", |
|
"EthereumStratum/1.0.0" |
|
], |
|
"a2eea0" |
|
], |
|
"error": null |
|
}\n |
|
|
|
Miner then authorize: |
|
{ |
|
"id": 2, |
|
"method": "mining.authorize", |
|
"params": [ |
|
"test", |
|
"password" |
|
] |
|
}\n |
|
|
|
And pool confirms: |
|
{ |
|
"id": 2, |
|
"result": true, |
|
"error": null |
|
}\n |
|
|
|
Pool sends difficulty: |
|
{ |
|
"id": null, |
|
"method": "mining.set_difficulty", |
|
"params": [ |
|
1.0 |
|
] |
|
}\n |
|
|
|
And job: |
|
{ |
|
"id": null, |
|
"method": "mining.notify", |
|
"params": [ |
|
"bf0488aa", |
|
"abad8f99f3918bf903c6a909d9bbc0fdfa5a2f4b9cb1196175ec825c6610126c", |
|
"fc12eb20c58158071c956316cdcd12a22dd8bf126ac4aee559f0ffe4df11f279", |
|
true |
|
] |
|
}\n |
|
|
|
After a while, miner finds share and submits it: |
|
{ |
|
"id": 3, |
|
"method": "mining.submit", |
|
"params": [ |
|
"test", |
|
"bf0488aa", |
|
"cfae7df760" |
|
] |
|
}\n |
|
|
|
Response from the pool: |
|
{ |
|
"id": 3, |
|
"result": true, |
|
"error": null |
|
}\n |
|
|
|
The share was valid considering data: |
|
seedhash=abad8f99f3918bf903c6a909d9bbc0fdfa5a2f4b9cb1196175ec825c6610126c |
|
headerhash=fc12eb20c58158071c956316cdcd12a22dd8bf126ac4aee559f0ffe4df11f279 |
|
nonce=a2eea0cfae7df760 |
|
|
|
Result is share with difficulty of 1.863 which is above 1.0. |
|
|
|
|
|
V. Planned improvements |
|
----------------------- |
|
|
|
Ethereum has RPC method eth_getBlockByNumber which can return some data about |
|
next block that is yet to be mined. Among data is next block number (block |
|
height). This number could be used instead of seedhash; every miner would then |
|
calculate seedhash on it's own thus bandwidth usage would be reduced even more. |
|
|
|
There are plans to make eth_getBlockTemplate method. When this is made, this |
|
stratum protocol may get very similar to standard stratum. |
|
|
|
|
|
VI. Contact |
|
----------- |
|
|
|
www.nicehash.com |
|
info@nicehash.com
|
|
|