Echelon Protocol
Version 1.0.4
The echelon specification repository can be found here.
The stratum protocol is used by ASIC miners, devices created specifically for performing Bitcoin mining.
The echelon protocol is a modified version of the stratum v1 protocol for mining nexa.
Miners use the echelon protocol to reach out to one or more servers (e.g. a mining pool) in order to obtain a mining candidate for a new block. The miner tests solutions by increasing the nonce until a candidate block that meets the specified difficulty requirements is successfully created.
Message Format
Echelon uses the JSON-RPC 2.0 message format. That is, JSON-encoded messages, separated by newline (line feed) characters. There are two high-level message formats: requests and responses.
Requests
Requests all contain the following fields:
Field | Format | Description |
---|---|---|
id | number or string | A message ID that must be unique per request that expects a response. For requests not expecting a response (called notifications), this is null. |
method | string | Indicates the type of request the message represents. |
params | array | Additional data which varies based on the request method. |
Responses
Responses all contain the following fields:
Field | Format | Description |
---|---|---|
id | number or string | The ID of the request that this message is a response to. |
result | any | Data being returned in response to the request. Must be present, but may be a string, number, array, object, or null. |
error | error array | Indicates that the request could not be fulfilled and provides information about what went wrong. |
Error Array Format
The error array is a JSON array containing the following elements:
Field | Format | Description |
---|---|---|
error code | number | An error code indicating the type of error. |
message | string | A description of the error. |
data | object | Additional data associated with the error (nullable). |
Example error: {"result":null,"id":2,"error":[24,"Unauthorized worker",null]}
Beyond those specified by JSON-RPC, the following error codes are used:
Code | Description |
---|---|
20 | Other/Unknown |
21 | Job not found (=stale) |
22 | Duplicate share |
23 | Low difficulty share |
24 | Unauthorized worker |
25 | Not subscribed |
Echelon Protocol Flow
Client Server
| |
| --------- mining.subscribe -------> |
| --------- mining.authorize -------> |
| <-------- mining.set_difficulty --- |
| |----
| <---------- mining.notify --------- |<--/
| |
| ---------- mining.submit ---------> |
Full Protocol
Client Methods
mining.subscribe
Upon connecting to a server, clients are expected to send a subscribe request, described as follows.
Field | Format | Description |
---|---|---|
method | string | "mining.subscribe" |
params[0] - user_agent_version | string | User agent name and version, separated by a forward slash (e.g. "nxminer/2.0.0"). |
Example request: {"id": 1, "method": "mining.subscribe", "params": ["nxminer/2.0.0"]}
In response, the server will send the following data in its result object, which is a JSON array:
Field | Format | Description |
---|---|---|
subscriptions | array | An array containing sub-array that described intended subscriptions. The first value in sub-arrays is the subscription type (e.g. "mining.set_difficulty"), the second is a subscription ID. |
extranonce | string | The 64 bit big endian hex encoded value that is to be used the first 8 bytes of the solution nonce. |
extranonce2_size | int | The number of bytes that the miner users for its extranonce2 counter. |
Example response: {"result":[[["mining.set_difficulty", 0.1 ]],"0000000000000001", 8],"id":1,"error":null}
mining.authorize
In order to authenticate itself, the client send an authorize message:
Field | Format | Description |
---|---|---|
method | string | "mining.authorize" |
params[0] - username | string | The client's user name. |
params[1] - password | string | The client's password (if required by the server). |
Example request: {"id": 1, "method": "mining.authorize", "params": ["username", "p4ssw0rd"]}
Response format:
Field | Format | Description |
---|---|---|
result | boolean | The value true if the client has been authorized; false otherwise. |
Example response: {"id": 2, "result": true, "error": null}
mining.submit
Once the client has completed a job (received via mining.notify following an accepted mining.authorize), it returns its result using a submit message. This message is also used to submit shares to a mining pool. The format is as follows:
Field | Format | Description |
---|---|---|
method | string | "mining.submit" |
params[0] - username | string | The client's user name. |
params[1] - job_id | string | The job ID for the work being submitted. |
params[2] - solution_nonce | string | A 128 bit hex encoded value where the first 64 bits are the extranonce and the second 64 bits are the miner nonce. |
params[3] - time | string | The 64 bit big endian hex-encoded value of the time. (same value as received in mining.notify) |
Example request: {"id": 1, "method": "mining.submit", "params": ["username", "4f", "000000000000000100003e05486566fd", "0000000063b1fb60"]}
Response format:
Field | Format | Description |
---|---|---|
result | boolean | The value true if the submission has been accepted; false if it was rejected. |
Example response: {"id": 2, "result": true, "error": null}
mining.suggest_difficulty(preferred share difficulty Number)
Used to indicate a preference for share difficulty to the pool. Servers are not required to honour this request, even if they support the stratum method.
Server Methods
mining.notify
Once a client successfully connects using the mining.subscribe and mining.authorize messages, the server may send a job to the client, informing it of everything it needs to know in order to mine a new block. The notify message is a notification (does not expect a response) and has the following format:
Field | Format | Description |
---|---|---|
method | string | "mining.notify" |
params[0] - job_id | string | The job ID for the job being sent in this message. |
params[1] - header_commitment | string | The 256 bit big endian hex-encoded header commitment. |
params[2] - nbits | string | The 32 bit big endian hex-encoded network difficulty required for the block. |
params[3] - time | string | The 64 bit big endian hex-encoded current time for the block. |
params[4] - clean | boolean string (true/false) | Indicates whether the client should forget any prior jobs. If true, the server will reject any submissions for prior jobs and the miner should forget any prior job IDs so that they can be reused by the server. |
Example request: {"id": null, "method": "mining.notify", "params": ["4f", "e9c64cfd6711c5eaa8d20dc4c4a430b1e22141ecc1ad701471492420432d8a4b", "1b02fab2", "0000000063b1fb60", false]}
mining.set_difficulty
The server can adjust the difficulty required for miner shares with the "mining.set_difficulty" method. The miner should begin enforcing the new difficulty on the next job received. Some pools may force a new job out when set_difficulty is sent, using clean_jobs to force the miner to begin using the new difficulty immediately.
Field | Format | Description |
---|---|---|
method | string | "mining.set_difficulty" |
params[0] - new_difficulty | number | The new difficulty threshold for share reporting. Shares are reported using the mining.submit message. |
Example request: { "id": null, "method": "mining.set_difficulty", "params": [2]}
mining.set_extranonce
These values, when provided, replace the initial subscription values beginning with the next mining.notify job.
Field | Format | Description |
---|---|---|
method | string | "mining.set_extranonce" |
params[0] - extranonce1 | string | The new 64 bit big endian hex encoded value that is to be used the first 8 bytes of the solution nonce. |
params[1] - extranonce2_size | number | The new size of extranonce2. |
Example request: { "id": null, "method": "mining.set_extranonce", "params": ["0000000000000002", 8]}
Full hashing examples
NexaPow uses the following C++ code to calculate mining hashes
// CHashWriter is a sha256 class that runs a double sha256 hash
CHashWriter ret(SER_GETHASH, 0);
// push header_commitment then the nonce into the hashing buffer
ret << header_commitment << nonce;
// returns a double sha256 for the mining_hash
uint256 mining_hash = ret.GetHash();
// h1 is a single sha256 of the mining_hash
uint256 h1 = sha256(mining_hash);
// make a private key
CKey k;
// Use mining_hash as a private key
k.Set(mining_hash.begin(), mining_hash.end(), false);
if (!k.IsValid())
{
// If key is invalid, POW fails
return false;
}
// byte array for signature
std::vector<uint8_t> vchSig;
// generate a signature from the h1 hash
if (!k.SignSchnorr(h1, vchSig))
{
return false; // Signing h1 with mining_hash failed
}
uint256 final_hash;
// CSHA256 is a sha256 class that runs a single sha256
CSHA256 sha;
// write the signature to the hash buffer
sha.Write(&vchSig[0], vchSig.size());
// single sha256 the signature bytes to get back to 32 bytes, store this hash in final_hash
sha.Finalize(final_hash.begin());
// final_hash is the the final result to be returned
return final_hash;
The mining pool provides the miner with header_commitment hash 0a4ac49b2d02e3c8d12c7093255ba7c49624f9c374d9f1c2f8e37c58705e74b0
and mining nonce 10000000000000001182dc5800000000
.
When these two values are used in the NexaPoW algorithm, the final result produced should be 00000042cbc240375242e14641488a0e2dca7b54458a2cea23dc1d2c178bb188
.
To assist with debugging this algorithm these are the different intermediary hashes and signature produced by the algorithm above.
Please note hashes are printed in big endian but internally should be little endian.
mining_hash: 7077c3549e088001ff681c2291bbc171f6ea681b5bc79bca9f2e0f563ad3dfef
h1: f97e4711d32f29f4f9f3aa254290eaf486330b3b43507cc03ba93b596c6cce36
vchSig: 93bb5bd98bb9d0817c5594782d4648a995e76755a3c94fdd96673115a06b8483efe485e73c1e4732ce9c34ef6891e7f25ff7c080aacbf71660bf782b067bc4f1
final_hash: 00000042cbc240375242e14641488a0e2dca7b54458a2cea23dc1d2c178bb188
Another example using pool provided header_commitment hash 0a4ac49b2d02e3c8d12c7093255ba7c49624f9c374d9f1c2f8e37c58705e74b0
and mining nonce 1000000000000000b787915d00000000
.
mining_hash: 5cddd556e7972ee8b3e4ce01f954336cbb223813c1f01c768f299b82f20a0ea9
h1: 6c55ec4a361007edaf6561e20a2eccfb51572309f66bf7b04aea315fadc039f9
vchSig: fc1894a100e6b33d19abac5289403b4c942d75d061b5453904be740681526cae30ed3a59f1a9d3ca165151ddb1ca3069de832cd5cc5fc95a7339f058f1fd155b
final_hash: 0000005f0b59e110863566e77d85e1b4fc713754e5c75f8fc3df44133866a669