1 changed files with 365 additions and 0 deletions
@ -0,0 +1,365 @@
|
||||
------------------------------------------------------------------------- |
||||
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 |
||||
Loading…
Reference in new issue