XELIS Stratum Protocol
Version: 0.1.1
Last Updated: 5/5/2024
Authors: Vipor.net (opens in a new tab)
This document describes a protocol, that allows a group of miners to connect to a server, which coordinates the distribution of work packages among miners.
The initial protocol was written for Bitcoin and contains several pieces that need adjustment in order to be usable with XELIS.
Specification
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 (opens in a new tab).
The stratum protocol mostly adheres to the JSON RPC 2.0 (opens in a new tab) specification.
Overview
Communication happens over a bidirectional channel with messages encoded as
JSON with LF
delimiter—in this document written as \n
.
Since requests can be handled out of order, each request in a session SHOULD
have an unique id
. In order to be able to match request and response,
responses MUST have the same id
as their matching request. Notifications
sent by the server or calls that do not trigger any response MAY have an id
of
null
.
For further details on the members of request and response objects consult the JSON RPC 2.0 specification (opens in a new tab).
Protocol flow example
The following shows what a session might look like from subscription to submitting a solution.
Client Server
| |
| --------- mining.subscribe -------> |
| --------- mining.authorize -------> |
| <-------- mining.set_difficulty --- |
| |----
| <---------- mining.notify --------- |<--/
| |
| ---------- mining.submit ---------> |
New difficulty protocol flow example
The following shows what communication may look like when a new difficulty is set for a miner.
Client Server
| |
| <-------- mining.set_difficulty --- |
| <---------- mining.notify --------- |
| |
| ---------- mining.submit ---------> |
Methods
- mining.subscribe
- mining.authorize
- mining.notify
- mining.submit
- mining.set_difficulty
- mining.set_extranonce
- mining.ping
- mining.pong
- mining.print
- mining.hashrate
Errors
Whenever an RPC call triggers an error, the response MUST include an error
field which maps to a list of the following values:
code
:int
message
:string
data
:object
{"id": 10, "result": null, "error": {"code": 20, "message": "Invalid request", "data": null}}
Errors SHOULD be identified by their code
and programs SHOULD do error handling based on the code
and not the message
.
Available error codes, in addition to the codes defined in the JSON RPC 2.0 specification, are:
20
- Other/Unknown21
- Job not found (=stale)22
- Duplicate share23
- Low difficulty share24
- Unauthorized worker
The message
field SHOULD be a concise description of the error for human
consumption.
Implementors MAY choose to include an optional data
object with additional
information relevant to the error.
Including null
value in error
object is against the JSON RPC spec. Error should only be included in the response when there is an actual error.
MinerWork
Structure
112
bytes total32
bytes (0-31
) Header work hash8
bytes (32-39
) timestamp provided in mining.notify8
bytes (40-47
) nonce miner value32
bytes (48-79
) extra nonce provided in mining.subscribe32
bytes (80-111
) public key provided in mining.subscribe
mining.subscribe
In order to initiate a session with the server, a client needs to call the subscribe method.
This method call will only be executed by clients.
Request:
{
"id": 1,
"method": "mining.subscribe",
"params": ["MyMiner/1.0.0", ["xel/v2"]]
}
id
:int
: request idmethod
:string
: RPC method nameparams
:[ string, [ string ] ]
- MUST be the name and version of the mining software in the given format or an empty string.
- OPTIONAL, specifies a list of supported mining algorithms. If omitted, a default algorithm
xel/v2
or the most recent algorithm will be used. As of 7/11/2024 XELIS only supports one algoxel/v2
Miners please use xel/v2
Pool operators, for backwards compatibility, you should also support xel/1
. The stratum protocol originally used xel/0
and xel/1
but the node uses xel/v1
and xel/v2
. As a pool operator, if a miner sends xel/1
you should consider this to be xel/v2
Response
{
"id": 1,
"result": [
"ABC123",
"EXTRANONCE",
32,
"7e40899c7bcc885fad6dd3bdc68fa73141c1d8b917a1f399afeb1fb191376b16"
]
}
id
:int
: request idresult
:[ string, string, int, string ]
:- This SHOULD be a unique session id
- Extra nonce for the miner to use (in hex format)
- The length of the extra nonce in bytes
- The public key to use (in hex format)
mining.authorize
Before a client can submit solutions to a server it MUST authorize at least one worker.
This method call will only be executed by clients.
Request
{
"id": 2,
"method": "mining.authorize",
"params": ["xel:WALLET_ADDRESS", "WORKER_NAME", "WORKER_PASSWORD"]
}
id
:int
: request idmethod
:string
: RPC method nameparams
:[ string, string, string ]
- The miner wallet address
- The worker name
- The worker password
Response
{"id": 2, "result": true }
id
:int
: request idresult
:boolean
:- MUST be
true
if the worker was authorized - MUST be
false
if the worker was not authorized - If the worker was not authorized, the server MUST respond with an error message
- MUST be
mining.notify
The notify call is used to supply a worker with new work to be processed.
This method call will only be executed by the server.
Request
{
"id": 1,
"method": "mining.notify",
"params": [
"abc123",
"19726D97F49",
"d9da51a0c3f8a1784911d370fdb617ea7f41581f5059d31e35f176b85efa5570",
"xel/0",
true
]
}
id
:int
: request idmethod
:string
: RPC method nameparams
:[ string, int, string, string, bool ]
- Job ID
- Timestamp milliseconds (in hex format)
- Header work hash (
32
bytes) - Blake3 hash of the block header (immutable) - Algorithm name
- A boolean indicating whether the miners job queue should be emptied or not ("clean jobs")
- Majority of the time this is meant for signifying to the miner that the block they are mining has already been found, and they should start mining on a new block height.
Miner should use the timestamp
and header work hash
to generate the MinerWork Structure, updating the nonce until a solution is found and then submit the nonce from any solutions found (below in mining.submit
).
Response
There is no explicit response for this call.
mining.submit
With this method a worker can submit solutions for the mining puzzle. This method call will only be executed by clients.
Request
{
"id": 4,
"method": "mining.submit",
"params": [
"WORKER_NAME",
"abc123",
"0011223344556677"
]
}
id
:int
: request idmethod
:string
: RPC method nameparams
:[ string, string, string ]
parameters- Worker name
- Job ID
- Miner nonce (in hex format)
Response
{"id": 4, "result": true}
id
:int
: request idresult
:bool
: submission accepted- MUST be
true
if accepted
- MUST be
mining.set_difficulty
The target difficulty for a share can change and a server needs to be able to notify clients of that.
This method call will only be executed by the server.
Request
{
"id": 1,
"method": "mining.set_difficulty",
"params": [1]
}
id
:int
: request idmethod
:string
: RPC method nameparams
:[ int ]
:- The target difficulty
Any subsequent jobs started by a client after receiving this update MUST honor the new target and servers will reject any shares below this difficulty.
This SHOULD be followed by a mining.notify
call.
Response
There is no explicit response for this call.
mining.set_extranonce
The extra nonce for a share can change and a server needs to be able to notify clients of that.
This method call will only be executed by the server.
Request
{
"id": 1,
"method": "mining.set_extranonce",
"params": ["EXTRANONCE", 32, "PUBLIC KEY"]
}
id
:int
: request idmethod
:string
: RPC method nameparams
:[ string, int, string ]
:- New extra nonce to use (in hex format)
- The length of the extra nonce in bytes
- New public key to use (in hex format). New public key parameter is optional and mandatory only if changed.
NOTE: If you don't want to update the public key, you can just send 2 parameters: ["EXTRANONCE", 32]
.
Any subsequent jobs started by a client after receiving this update MUST honor the new extranonce and public key.
Servers will reject any shares below difficulty.
This SHOULD be followed by a mining.notify
call.
Response
There is no explicit response for this call.
mining.ping
With this method a pool can check if a miner connection is still alive. This method call will only be executed by servers.
Request
{"id": 4, "method": "mining.ping"}
id
:int
]: request idmethod
:string
]: RPC method name
Response
No response is required for this call. The client should respond with a mining.pong
call.
mining.pong
With this method a client/miner can respond to signify that the connection is still alive. This method call will only be executed by clients.
Request
{"id": 4, "method": "mining.pong"}
id
:int
]: request idmethod
:string
]: RPC method name
Response
No response is required for this call.
Optional
The methods below are optional, but preferred.
mining.print
With this method a server can send a message to the miner to print on screen.
Request
{"id": 4, "method": "mining.print", "params": [0, "Your wallet address is invalid, please check before attempting to reconnect."]}
id
:int
]: request idmethod
:string
]: RPC method nameparams
: (int
,string
) ]: list of method parameters- Print level
- Message to print
Print Levels
0
- Information1
- Warning2
- Error3
- Debug
Response
No response is required for this call.
mining.hashrate
With this method a client/miner can submit the reported hashrate (in miner) to the pool (similar to eth_submitHashrate
in ethash).
Request
{"id": 4, "method": "mining.hashrate", "params": [1000]}
id
:int
]: request idmethod
:string
]: RPC method nameparams
: (int
,string
) ]: list of method parameters- Reported hashrate in H/s
Response
No response is required for this call.