EIP-1571: EthereumStratum/2.0.0
作者 | Andrea Lanfranchi, Pawel Bylica, Marius Van Der Wijden |
---|---|
讨论-To | https://github.com/AndreaLanfranchi/EthereumStratum-2.0.0/issues |
状态 | Stagnant |
类型 | Standards Track |
分类 | Interface |
创建日期 | 2018-11-09 |
英文版 | https://eips.ethereum.org/EIPS/eip-1571 |
摘要
This draft contains the guidelines to define a new standard for the Stratum protocol used by Ethereum miners to communicate with mining pool servers.
Conventions
The key words MUST
, MUST NOT
, REQUIRED
, SHALL
, SHALL NOT
, SHOULD
, SHOULD NOT
, RECOMMENDED
, MAY
, and OPTIONAL
in this document are to be interpreted as described in RFC 2119. The definition mining pool server
, and it’s plural form, is to be interpreted as work provider
and later in this document can be shortened as pool
or server
. The definition miner(s)
, and it’s plural form, is to be interpreted as work receiver/processor
and later in this document can be shortened as miner
or client
.
基本原理
Ethereum does not have an official Stratum implementation yet. It officially supports only getWork which requires miners to constantly pool the work provider. Only recently go-ethereum have implemented a push mechanism to notify clients for mining work, but whereas the vast majority of miners do not run a node, it’s main purpose is to facilitate mining pools rather than miners. The Stratum protocol on the other hand relies on a standard stateful TCP connection which allows two-way exchange of line-based messages. Each line contains the string representation of a JSON object following the rules of either JSON-RPC 1.0 or JSON-RPC 2.0. Unfortunately, in absence of a well defined standard, various flavours of Stratum have bloomed for Ethereum mining as a derivative work for different mining pools implementations. The only attempt to define a standard was made by NiceHash with their EthereumStratum/1.0.0 implementation which is the main source this work inspires from. Mining activity, thus the interaction among pools and miners, is at it’s basics very simple, and can be summarized with “please find a number (nonce) which coupled to this data as input for a given hashing algorithm produces, as output, a result which is below a certain target”. Other messages which may or have to be exchanged among parties during a session are needed to support this basic concept. Due to the simplicity of the subject, the proponent, means to stick with JSON formatted objects rather than investigating more verbose solutions, like for example Google’s Protocol Buffers which carry the load of strict object definition.
Stratum design flaws
The main Stratum design flaw is the absence of a well defined standard. This implies that miners (and mining software developers) have to struggle with different flavours which make their life hard when switching from one pool to another or even when trying to “guess” which is the flavour implemented by a single pool. Moreover all implementations still suffer from an excessive verbosity for a chain with a very small block time like Ethereum. A few numbers may help understand. A normal mining.notify
message weigh roughly 240 bytes: assuming the dispatch of 1 work per block to an audience of 50k connected TCP sockets means the transmission of roughly 1.88TB of data a month. And this can be an issue for large pools. But if we see the same figures the other way round, from a miner’s perspective, we totally understand how mining decentralization is heavily affected by the quality of internet connections.
Sources of inspiration
规范
The Stratum protocol is an instance of JSON-RPC-2.0. The miner is a JSON-RPC client, and the server is a JSON-RPC server. All communications exist within the scope of a session
. A session starts at the moment a client opens a TCP connection to the server till the moment either party do voluntary close the very same connection or it gets broken. Servers MAY support session resuming if this is initially negotiated (on first session handshaking) between the client and the server. During a session all messages exchanged among server and client are line-based which means all messages are JSON strings terminated by ASCII LF character (which may also be denoted as \n
in this document). The LF character MUST NOT appear elsewhere in a message. Client and server implementations MUST assume that once they read a LF character, the current message has been completely received and can be processed. Line messages are of three types :
Requests
: messages for which the issuer expects a response. The receiver MUST reply back to any request individuallyResponses
: solicited messages by a previous request. The responder MUST label the response with the same identifier of the originating request.Notifications
: unsolicited messages for which the issuer is not interested nor is expecting a response. Nevertheless a response (eg. an aknowledgement) MAY be sent by the receiver.
During a session
both parties CAN exchange messages of the above depicted three types.
JSON-RPC-2.0 Compliances
As per JSON-RPC-2.0 specification requests and responses differ from notifications by the identifier (id
) member in the JSON object:
- Requests MUST have an
id
member - Responses MUST have an
id
member valued exactly as theid
member of the request this response is for - Notifications MUST NOT have an
id
member
JSON-RPC-2.0 Defiances
In order to get the most concise messages among parties of a session/conversation this implementation enforces the following defiances :
- JSON member
jsonrpc
(always valued to “2.0”) MUST ALWAYS BE OMITTED - JSON member
id
MUST NOT benull
. When member is present, mandatorily in requests and responses, it MUST be valued to an integer Number ranging from 0 to 65535. Please note that a message with"id": 0
MUST NOT be interpreted as a notification: it’s a request with identifier 0 - JSON member
id
MUST be only of type primitive number. The removal of other identifier types (namely strings) is due to the need to reduce the number of bytes transferred.
Conventions
- The representation of a JSON object is, at it’s base, a string
- The conversation among the client and the server is made of strings. Each string ending with a LF (ASCII char 10) denotes a
line
. Each line MUST contain only one JSON root object. Eventually the root object MAY contain additional JSON objects in it’s members. - Aside the
LF
delimiter eachline
MUST be made of printable ASCII chars in the range 32..126 - It’s implicit and mandatory that each line message corresponds to a well formatted JSON object: see JSON documentation
- JSON objects are made of
members
which can be of type : primitive of string/number, JSON object, JSON arrays - JSON
member
’s names are strings which MUST be composed of printable chars only in the ASCII range 48..57 (numbers) and 97..122 (lower case letters). - JSON
member
’s names MUST NOT begin with a number. - JSON values
arrays
: although the JSON notation allows the insertion of different data types within the same array, this behavior is generally not accepted in coding languages. Due to this, by the means of EthereumStratum/2.0.0, all implementers MUST assume that an array is made of elements of the very same data type. - JSON values
booleans
: the JSON notation allows to express boolean values astrue
orfalse
. In EthereumStratum/2.0.0, for better compatibility within arrays, boolean values will be expressed in the hex form of “0” (false) or “1” (true) - JSON values
strings
: any string value MUST be composed of printable ASCII chars only in the ASCII range 32..126. Each string is delimited by a"
(ASCII 34) at the beginning and at the end. Should the string value contain a"
this must be escaped as\"
- Hex values : a Hexadecimal representation of a number is actually a string data type. As a convention, and to reduce the number of transmitted bytes, the prefix “0x” MUST always be omitted. In addition any hex number MUST be transferred only for their significant part i.e. the non significant zeroes MUST be omitted (example : the decimal
456
must be represented as"1c8"
and not as"01c8"
although the conversion produces the same decimal value). This directive DOES NOT APPLY to hashes and extranonces - Hex values casing : all letters in Hexadecimal values MUST be lower case. (example : the decimal
456
must be represented as"1c8"
and not as"1C8"
although the conversion produces the same decimal value). This directive DOES NOT APPLY to hashes. - Numbers : any non-fractional number MUST be transferred by it’s hexadecimal representation
Requests
The JSON representation of request
object is made of these parts:
- mandatory
id
member of type Integer : the identifier established by the issuer - mandatory
method
member of type String : the name of the method to be invoked on the receiver side - optional
params
member : in case the method invocation on the receiver side requires the application of additional parameters to be executed. The type CAN be Object (with named members of different types) or Array of single type. In case of an array the parameters will be applied by their ordinal position. If the method requested for invocation on the receiver side does not require the application of additional parameters this member MUST NOT be present. The notation"params" : null
IS NOT PERMITTED
Responses
The JSON representation of response
object is made of these parts:
- mandatory
id
member of type Integer : the identifier of the request this response corresponds to - optional
error
member : whether an error occurred during the parsing of the method or during it’s execution this member MUST be present and valued. If no errors occurred this member MUST NOT be present. For a detailed structure of theerror
member see below. - optional
result
member : This has to be set, if the corresponding request requires a result from the user. If no errors occurred by invoking the corresponding function, this member MUST be present even if one or more information are null. The type can be of Object or single type Array or Primitive string/number. If no data is meant back for the issuer (the method is void on the receiver) or an error occurred this member MUST NOT be present.
You’ll notice here some differences with standard JSON-RPC-2.0. Namely the result member is not always required. Basically a response like this :
{"id": 2}
means “request received and processed correctly with no data to send back”.
To better clarify the concept and clear the field of free interpretations let’s take another example of wrong response
{"id": 2, "result": false}
This response syntax leaves room to many interpretations : is it an error ? is false
the legit response value to the issued request ?
For this reason responses, we reiterate, MUST BE of two types:
- success responses : no error occurred during the processing, the request was legit, syntactically correct, and the receiver had no issues processing it. This kind of responses MUST NOT have the
error
member and MAY have theresult
member if a value is expected back to the issuer. - failure responses : something wrong with the request, it’s syntax, it’s validity scope, or server processing problems. This kind of responses MUST HAVE the
error
member and MAY have theresult
member.
The latter deserves a better explanation: failure responses can be distinguished by a severity degree. Example 1 : a client submits a solution and server rejects it cause it’s not below target. Server MUST respond like this
{
"id": 31,
"error": {
"code": 406,
"message" : "Bad nonce"
}
}
Example 2 : a client submits a solution and server accepts it but it accounts the share as stale. Server MUST respond like this
{
"id": 31,
"error": {
"code": 202,
"message" : "Stale"
}
}
Example 3 : a client submits an authorization request specifying an invalid workername. Server authorizes the account but rejects worker name. Server MUST respond like this
{
"id": 1,
"error": {
"code": 215,
"message" : "Invalid Worker Name"
}
}
Example 1 depicts the condition of a severe failure while Example 2 and 3 depict a situation where the request has been accepted and processed properly but the result MAY NOT be what expected by the client. It’s up to the client to evaluate the severity of the error and decide whether to proceed or not.
Using proper error codes pools may properly inform miners of the condition of their requests. Error codes MUST honor this scheme:
- Error codes 2xx : request accepted and processed but some additional info in the
error
member may give hint - Error codes 3xx : server could not process the request due to a lack of authorization by the client
- Error codes 4xx : server could not process the request due to syntactic problems (method not found, missing params, wrong data types ecc.) or passed
param
values are not valid. - Error codes 5xx : server could not process the request due to internal errors
Notifications
A notification message has the very same representation of a request
with the only difference the id
member MUST NOT be present. This means the issuer is not interested nor expects any response to this message. It’s up to the receiver to take actions accordingly. For instance the receiver MAY decide to execute the method, or, in case of errors or methods not allowed, drop the connection thus closing the session.
Error member
As seen above a response
MAY contain an error
member. When present this member MUST be an Object with:
- mandatory member
code
: a Number which identifies the error occurred - mandatory member
message
: a short human readable sentence describing the error occurred - optional member
data
: a Structured or Primitive value that contains additional information about the error. The value of this member is defined by the Server (e.g. detailed error information, nested errors etc.).
Protocol Flow
- Client starts session by opening a TCP socket to the server
- Client advertises and request protocol compatibility
- Server confirms compatibility and declares ready
- Client starts/resumes a session
- Client sends request for authorization for each of it’s workers
- Server replies back with responses for each authorization
- Server sends
mining.set
for constant values to be adopted for following mining jobs - Server sends
mining.notify
with minimal job info - Client mines on job
- Client sends
mining.submit
if any solution found for the job - Server replies whether solution is accepted
- Server optionally sends
mining.set
for constant values to be adopted for following mining jobs (if something changed) - Server sends
mining.notify
with minimal job info - … (continue)
- Eventually either party closes session and TCP connection
Session Handling - Hello
One of the worst annoyances until now is that server, at the very moment of socket connection, does not provide any useful information about the stratum flavour implemented. This means the client has to start a conversation by iteratively trying to connect via different protocol flavours. This proposal amends the situation making mandatory for the server to advertise itself to the client. When a new client connects to the server, the server MUST send a mining.hello
notification :
It’s been noted that charging the server of the duty to advertise itself as first message of the conversation could potentially be harmful in respect of traffic amplification attacks using spoofed IP addresses or in traditional DDos attacks where an attacker need to spend very little resources to force the server to send a large packet back. For this reason the duty of first advertisement is kept on client which will issue a mining.hello
request like this:
{
"id" : 0,
"method": "mining.hello",
"params":
{
"agent": "ethminer-0.17",
"host" : "somemininigpool.com",
"port" : "4d2",
"proto": "EthereumStratum/2.0.0"
}
}
The params
member object has these mandatory members:
agent
(string) the mining software versionhost
(string) the host name of the server this client is willing to connect toport
(hex) the port number of the server this client is willing to connect toproto
(string) which reports the stratum flavour requested and expected to be implemented by the server;
The rationale behind sending host and port is it enables virtual hosting, where virtual pools or private URLs might be used for DDoS protection, but that are aggregated on Stratum server backends. As with HTTP, the server CANNOT trust the host string. The port is included separately to parallel the client.reconnect method (see below).
If the server is prepared to start/resume a session with such requirements it MUST reply back with a response like this:
{
"id" : 0,
"result":
{
"proto" : "EthereumStratum/2.0.0",
"encoding" : "gzip",
"resume" : "1",
"timeout" : "b4",
"maxerrors" : "5",
"node" : "Geth/v1.8.18-unstable-f08f596a/linux-amd64/go1.10.4"
}
}
Where the result
is an object made of 5 mandatory members
proto
(string) which MUST match the exact version requested by the clientencoding
(string) which value states whether or not all next messages should be gzip compressed or not. Possible values are “gzip” or “plain”resume
(hex) which value states whether or not the host can resume a previously created session;timeout
(hex) which reports the number of seconds after which the server is allowed to drop connection if no messages from the clientmaxerrors
(hex) the maximum number of errors the server will bear before abruptly close connectionnode
(string) the node software version underlying the pool
When the server replies back with "encoding" : "gzip"
to the client, both parties MUST gzip compress all next messages. In case the client is not capable of compression it MUST close the connection immediately. Should the server, after this reply, receive other messages as plain text, it MUST close the connection.
Eventually the client will continue with mining.subscribe
(further on descripted)
Otherwise, in case of errors or rejection to start the conversation, the server MAY reply back with an error giving the other party useful information or, at server’s maintainers discretion, abruptly close the connection.
{
"id" : 0,
"error":
{
"code": 400,
"message" : "Bad protocol request"
}
}
or
{
"id" : 0,
"error":
{
"code": 403,
"message" : "Forbidden - Banned IP address"
}
}
The above two JSON error values are only samples Eventually the server will close the connection.
Why a pool should advertise the node’s version ? It’s a matter of transparency : miners should know whether or not pool have upgraded to latest patches/releases for node’s software.
Session Handling - Bye
Disconnection are not gracefully handled in Stratum. Client disconnections from pool may be due to several errors and this leads to waste of TCP sockets on server’s side which wait for keepalive timeouts to trigger. A useful notification is mining.bye
which, once processed, allows both parties of the session to stop receiving and gracefully close TCP connections
{
"method": "mining.bye"
}
The party receiving this message aknowledges the other party wants to stop the conversation and closes the socket. The issuer will close too. The explicit issuance of this notification implies the session gets abandoned so no session resuming will be possible even on server which support session-resuming. Client reconnecting to the same server which implements session resuming SHOULD expect a new session id and MUST re-authorize all their workers.
Session Handling - Session Subscription
After receiving the response to mining.hello
from server, the client, in case the server does support session resuming MAY request to resume a previously interrupted session with mining.subscribe
request:
{
"id": 1,
"method": "mining.subscribe",
"params": "s-12345"
}
where params
is the id of the session the client wants to resume.
Otherwise, if client wants to start a new session OR server does not support session resuming, the request of subscription MUST omit the params
member:
{
"id": 1,
"method": "mining.subscribe"
}
Session Handling - Response to Subscription
A server receiving a client session subscription MUST reply back with
{
"id": 1,
"result": "s-12345"
}
A server receiving a subscription request with params
being a string holding the session id. This cases may apply
- If session resuming is not supported
result
will hold a new session Id which MUST be a different value from thesession
member issued by client in previousmining.subscribe
method - If session resuming is supported it will retrieve working values from cache and
result
will have the same id requested by the client. This means a session is “resumed”: as a consequence the server CAN start pushing jobs omitting to precede them withmining.set
(see below) and the client MUST continue to use values lastly received within the same session scope. In addition the client CAN omit to re-authorize all it’s workers. - If session resuming is supported but the requested session has expired or it’s cache values have been purged
result
will hold a new session Id which MUST be a different value from thesession
member issued by client in previousmining.subscribe
method. As a consequence the server MUST wait for client to request authorization for it’s workers and MUST sendmining.set
values before pushing jobs. The client MUST prepare for a new session discarding all previously cached values (if any).
A server implementing session-resuming MUST cache :
- The session Ids
- Any active job per session
- The extraNonce
- Any authorized worker
Servers MAY drop entries from the cache on their own schedule. It’s up to server to enforce session validation for same agent and/or ip.
A client which successfully subscribes and resumes session (the session
value in server response is identical to session
value requested by client on mining.subscribe
) CAN omit to issue the authorization request for it’s workers.
Session Handling - Noop
There are cases when a miner struggles to find a solution in a reasonable time so it may trigger the timeout imposed by the server in case of no communications (the server, in fact, may think the client got disconnected). To mitigate the problem a new method mining.noop
(with no additional parameters) may be requested by the client.
{
"id": 50,
"method": "mining.noop"
}
Session Handling - Reconnect
Under certain circumstances the server may need to free some resources and or to relocate miners to another machine. Until now the only option for servers was to abruptly close the connection. On the miner’s side this action is interpreted as a server malfunction and they, more often than not, switch to a failover pool. The implementation of the notification mining.reconnect
helps client to better merge with logic of handling of large mining pools.
{
"method": "mining.reconnect",
"params": {
"host": "someotherhost.com",
"port": "d80",
"resume": "1"
}
}
This notification is meant only from servers to clients. Should a server receive such a notification it will simply ignore it. After the notification has been properly sent, the server is ALLOWED to close the connection, while the client will take the proper actions to reconnect to the suggested end-point. The host
member in params
object SHOULD report an host DNS name and not an IP address: TLS encrypted connections require to validate the CN name in the certificate which, 99% of the cases, is an host name. The third member resume
of the params
object sets whether or not the receiving server is prepared for session resuming. After this notification has been issued by the server, the client should expect no further messages and MUST disconnect.
Workers Authorization
The miner MUST authorize at least one worker in order to begin receiving jobs and submit solutions or hashrates. The miner MAY authorize multiple workers in the same session. The server MUST allow authorization for multiple workers within a session and MUST validate at least one authorization from the client before starting to send jobs. A worker
is a tuple of the address where rewards must be credited coupled with identifier of the machine actually doing the work. For Ethereum the most common form is <account>.<MachineName>
. The same account can be bound to multiple machines. For pool’s allowing anonymous mining the account is the address where rewards must be credited, while, for pools requiring registration, the account is the login name. Each time a solution is submitted by the client it must be labelled with the Worker identifier. It’s up to server to keep the correct accounting for different addresses.
The syntax for the authorization request is the following:
{
"id": 2,
"method": "mining.authorize",
"params": ["<account>[.<MachineName>]", "password"]
}
params
member must be an Array of 2 string elements. For anonymous mining the “password” can be any string value or empty but not null. Pools allowing anonymous mining will simply ignore the value. The server MUST reply back either with an error or, in case of success, with
{
"id": 2,
"result": "w-123"
}
Where the result
member is a string which holds an unique - within the scope of the session
- token which identifies the authorized worker. For every further request issued by the client, and related to a Worker action, the client MUST use the token given by the server in response to an mining.authorize
request. This reduces the number of bytes transferred for solution and /or hashrate submission.
If client is resuming a previous session it CAN omit the authorization request for it’s workers and, in this case, MUST use the tokens assigned in the originating session. It’s up to the server to keep the correct map between tokens and workers. The server receiving an authorization request where the credentials match previously authorized ones within the same session MUST reply back with the previously generated unique token.
Prepare for mining
A lot of data is sent over the wire multiple times with useless redundancy. For instance the seed hash is meant to change only every 30000 blocks (roughly 5 days) while fixed-diff pools rarely change the work target. Moreover pools must optimize the search segments among miners trying to assign to every session a different “startNonce” (AKA extraNonce). For this purpose the notification
method mining.set
allows to set (on miner’s side) only those params which change less frequently. The server will keep track of seed, target and extraNonce at session level and will push a notification mining.set
whenever any (or all) of those values change to the connected miner.
{
"method": "mining.set",
"params": {
"epoch" : "dc",
"target" : "0112e0be826d694b2e62d01511f12a6061fbaec8bc02357593e70e52ba",
"algo" : "ethash",
"extranonce" : "af4c"
}
}
At the beginning of each session
the server MUST send this notification before any mining.notify
. All values passed by this notification will be valid for all NEXT jobs until a new mining.set
notification overwrites them. Description of members is as follows:
- optional
epoch
(hex) : unlike all actual Stratum implementations the server should inform the client of the epoch number instead of passing the seed hash. This is enforced by two reasons : the main one is that client has only one way to compute the epoch number and this is by a linear search from epoch 0 iteratively trying increasing epochs till the hash matches the seed hash. Second reason is that epoch number is more concise than seed hash. In the end the seed hash is only transmitted to inform the client about the epoch and is not involved in the mining algorithm. - optional
target
(hex) : this is the boundary hash already adjusted for pool difficulty. Unlike in EthereumStratum/1.0.0, which provides amining.set_difficulty
notification of an index of difficulty, the proponent opt to pass directly the boundary hash. If omitted the client MUST assume a boundary of"0x00000000ffff0000000000000000000000000000000000000000000000000000"
- optional
algo
(string) : the algorithm the miner is expected to mine on. If omitted the client MUST assume"algo": "ethash"
- optional
extranonce
(hex) : a starting search segment nonce assigned by server to clients so they possibly do not overlap their search segments. If server wants to “cancel” a previously set extranonce it must pass this member valued as an empty string.
Whenever the server detects that one, or two, or three or four values change within the session, the server will issue a notification with one, or two or three or four members in the param
object. For this reason on each new session the server MUST pass all four members. As a consequence the miner is instructed to adapt those values on next job which gets notified. The new algo
member is defined to be prepared for possible presence of algorithm variants to ethash, namely ethash1a or ProgPow. Pools providing multicoin switching will take care to send a new mining.set
to miners before pushing any job after a switch. The client which can’t support the data provided in the mining.set
notification MAY close connection or stay idle till new values satisfy it’s configuration (see mining.noop
). All client’s implementations MUST be prepared to accept new extranonces during the session: unlike in EthereumStratum/1.0.0 the optional client advertisement mining.extranonce.subscribe
is now implicit and mandatory.
The miner receiving the extranonce
MUST initialize the search segment for next job resizing the extranonce to a hex of 16 bytes thus appending as many zeroes as needed. Extranonce “af4c” means “search segment of next jobs starts from 0xaf4c000000000000” If extranonce
is valued to an empty string, or it’s never been set within the session scope, the client is free pick any starting point of it’s own search segment on subsequent mining.notify
jobs.
A detail of “extranonce”
Miners connected to a pool might likely process the very same nonces thus wasting a lot of duplicate jobs. A nonce
is any valid number which, applied to algorithm and job specifications, produces a result which is below a certain target. For every job pushed by server to client(s) there are 2^64 possible nonces to test.
To be noted that :
- Any nonce in the 2^64 has the very same possibility to be the right one.
- A certain hashing job can be solved by more than one nonce
Every “test” over a number is called a hash. Assuming a miner should receive a job for each block and considering the actual average block time of 15 seconds that would mean a miner should try
( 2^64 / 15 ) / 1T ~ 1,229,782.94 TeraHashes per second
This computation capacity is well beyond any miner on the market (including ASICs). For this reason single miners can process only small chunks (segments) of this humongous range. The way miners pick the segments to search on is beyond the scope of this work. Fact is as miners are not coordinated there is no knowledge - for a single miner - of segments picked by other miners. Extranonce concept is here to mitigate this possibility of duplicate jobs charging the server (the work provider) to give miners, at the maximum possible extent, different segments to search on.
Giving the above assumptions we can depict a nonce as any number in the hex range :
Min 0x0000000000000000
Max 0xffffffffffffffff
the prefix 0x is voluntarily inserted here only to give a better visual representation.
The extranonce
is, at it’s basics, the message of the server saying the client “I give you the first number to start search from”. More in detail the extranoce
is the leftmost part of that number. Assume a pool notifies the client the usage of extranonce ab5d
this means the client will see it’s search segment narrowed as
Min 0xab5d000000000000
Max 0xab5dffffffffffff
Pushing an extranonce of 4 bytes (like in the example) will give pool the possibility to separate segment 65535 different miners ( or if you prefer 0xffff miners ) while leaving the miner still a segment of 2^48 possible nonces to search on. Recalculating, as above, the computation capacity needed to search this segment we get
( 2^48 / 15 ) / 1T ~ 18.76 TeraHashes per second
Which is still a wide segment where miners can randomly (or using other ergodic techniques) pick their internal search segments.
Extranonce MUST be passed with all relevant bytes (no omission of left zeroes) for a specific reason. Assume an extranonce of “01ac” : it has the same decimal value of “1ac” but the number of bytes changes thus changing available search segment
When "01ac" When "1ac"
Segment is Segment is
Min 0x01ac000000000000 Min 0x1ac0000000000000
Max 0x01acffffffffffff Max 0x1acfffffffffffff
As you can see resulting segments are quite different
This all said pools (server), when making use of extranonce, MUST observe a maximum length of 6 bytes (hex).
Jobs notification
When available server will dispatch jobs to connected miners issuing a mining.notify
notification.
{
"method": "mining.notify",
"params": [
"bf0488aa",
"6526d5"
"645cf20198c2f3861e947d4f67e3ab63b7b2e24dcc9095bd9123e7b33371f6cc",
"0"
]
}
params
member is made of 4 mandatory elements:
- 1st element is jobId as specified by pool. To reduce the amount of data sent over the wire pools SHOULD keep their job IDs as concise as possible. Pushing a Job id which is identical to headerhash is a bad practice and is highly discouraged.
- 2nd element is the hex number of the block id
- 3rd element is the headerhash.
- 4th element is an hex boolean indicating whether or not eventually found shares from previous jobs will be accounted for sure as stale.
Solution submission
When a miner finds a solution for a job he is mining on it sends a mining.submit
request to server.
{
"id": 31,
"method": "mining.submit",
"params": [
"bf0488aa",
"68765fccd712",
"w-123"
]
}
First element of params
array is the jobId this solution refers to (as sent in the mining.notify
message from the server). Second element is the miner nonce
as hex. Third element is the token given to the worker previous mining.authorize
request. Any mining.submit
request bound to a worker which was not successfully authorized - i.e. the token does not exist in the session - MUST be rejected.
You’ll notice in the sample above the miner nonce
is only 12 bytes wide (should be 16). Why ? That’s because in the previous mining.set
the server has set an extranonce
of af4c
. This means the full nonce is af4c68765fccd712
In presence of extranonce the miner MUST submit only the chars to append to the extranonce to build the final hex value. If no extranonce is set for the session or for the work the miner MUST send all 16 bytes.
It’s server duty to keep track of the tuples job ids <-> extranonces
per session.
When the server receives this request it either responds success using the short form
{"id": 31}
or, in case of any error or condition with a detailed error object
{
"id": 31,
"error": {
"code": 404,
"message" : "Job not found"
}
}
Client should treat errors as “soft” errors (stales) or “hard” (bad nonce computation, job not found etc.). Errors in 5xx range are server errors and suggest the miner to abandon the connection and switch to a failover.
Hashrate
Most pools offer statistic information, in form of graphs or by API calls, about the calculated hashrate expressed by the miner while miners like to compare this data with the hashrate they read on their devices. Communication about parties of these information have never been coded in Stratum and most pools adopt the method from getWork named eth_submitHashrate
. In this document we propose an official implementation of the mining.hashrate
request. This method behaves differently when issued from client or from server.
Client communicates it’s hashrate to server.
{
"id" : 16,
"method": "mining.hashrate",
"params": [
"500000",
"w-123"
]
}
where params
is an array made of two elements: the first is a hexadecimal string representation (32 bytes) of the hashrate the miner reads on it’s devices and the latter is the authorization token issued to worker this hashrate is refers to (see above for mining.authorization
). Server MUST respond back with either an aknowledgment message
{"id": 16 }
Optionally the server can reply back reporting it’s findings about calculated hashrate for the same worker.
{
"id": 16,
"result" : [
"4f0000",
"w-123"
]
}
In case of errors - for example when the client submits too frequently - with
{
"id": 16,
"error" : {
"code": 220,
"message": "Enhance your calm. Too many requests"
}
}
Server communicates hashrate to client
Optionally the server can notify client about it’s overall performance (according to schedule set on server) with a mining.hashrate
notification composed like this
{
"method": "mining.hashrate",
"params": {
"interval": 60,
"hr": "500000",
"accepted": [3692,20],
"rejected": 0,
}
}
Where params
is an object which holds these members for values of the whole session:
interval
(number) the width, in minutes, of the observation window. “in the last x minutes we calculated …”hr
(hex) representation of the hashrate the pool has calculated for the mineraccepted
is an array of two number elements : the first is the overall count of accepted shares and the second is the number of stale shares. The array must be interpreted as “total accepted of which x are stale”rejected
(number) the overall number of rejected shares
The client will eventually take internal actions to reset/restart it’s workers.
版权声明
Copyright and related rights waived via CC0.
参考文献
Please cite this document as:
Andrea Lanfranchi, Pawel Bylica, Marius Van Der Wijden, "EIP-1571: EthereumStratum/2.0.0 [DRAFT]," Ethereum Improvement Proposals, no. 1571, November 2018. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-1571.