#
Stratum Protocol
Messages are newline ("\n"
) terminated json strings sent over plain TCP with optional TLS encryption. URI scheme is stratum+tcp
for plain TCP and stratum+ssl
or stratum+tls
if TLS encryption is used (for some reason "ssl
" is more prevalent than "tls
" as URI scheme despite in fact TLS is actually used).
#
Establishing a stratum connection
After establishing a TCP connection (and optionally TLS) the first message is sent from the Client and must be of type mining.subscribe
:
#
Mining.subscribe
#
Request from client:
{
"id": 1,
"method": "mining.subscribe",
"params": [
"MinerName/1.0.0", # user agent / version
"<suggested session id>" # optional suggested session Id
]
}
#
Response from pool:
{
"id": 1, # same as "id" in the request
"result": [
[
[
"mining.notify",
"extra1hex" # session ID, often just equal to the extra nonce 1
]
],
"extra1hex", # extranonce 1 in hex
2 # size of extranonce2
],
"error": null
}
#
Mining authorize
The next message is again send from the client and must have "method"
field equal to "mining.authorize"
:
#
Request from client:
{
"id": 2,
"method": "mining.authorize",
"params": [
"address.worker", # user name, convention is to specify address and worker id
"password" # password
]
}
#
Response from pool:
{
"id": 2, # same "id" as in the request
"result": true,
"error": null
}
Now the connection is established. The pool n
#
Events pushed from pool server to clients
There are two kind of events that sent from the pool: "mining.notify"
and "mining.set_difficulty"
.
#
Mining.notify
{
"id": null,
"method": "mining.notify",
"params": [
"jobId", # jobId has to be sent back on submission
"prevHash", # hex encoded previous hash in block header
"merklePrefix", # hex encoded prefix of
"version", # hex encoded block version
"nbits", # hex encoded nbits, difficulty target
"ntime", # hex encoded ntime, timestamp in block header
false # clean? If yes, discard old jobs.
]
}
#
Notable differences from Bitcoin's Stratum protocol:
This method has only 7 parameters instead of 9 parameters in Bitcoin's stratum protocol. Bitcoin's stratum protocol's third (coinbase 1) and fourth (coinbase 2) parameters are not necessary in Warthog. Furthermore instead of Bitcoin's Merkle branches parameter we have a Merkle prefix parameter. Merkle root is computed as follows:
#
Merkle root computation
Merkle root is sha256(merklePrefix + extranonce1 + extranonce2)
. Miners can choose extranonce2 arbitrarily (with length specified by pool) to generate different Merkle roots.
#
Header structure
The parameters sent in a "mining.notify"
event and a 4-byte nonce
selected by the miner can be used to form a header to be hashed by the miner as follows:
#
Mining.set_difficulty
{
"id": null,
"method": "mining.set_difficulty",
"params": [
100000 # difficulty
]
}
#
Notable differences from Bitcoin's Stratum protocol
In contrast to Bitcoin's stratum protocol the target is just the inverse of the difficulty. In Bitcoin there is an additional factor of 2^32 involved for historical reasons. Since Warthog was written from scratch, it not carry this historical burden.
This means the miner must meet the target 1/difficulty
to mine a share.
#
Events pushed from miner to pool
#
Mining.submit
When the miner has found nonce and extranonce2 such that the block is
{
"id": 4,
"method": "mining.submit",
"params": [
"jobId", # jobId from mining.notify
"0000", # extranonce2 hex
"a5b378fe", # time hex (in shifupool equal to ntime from mining.notify)
"a28a04a2" # nonce hex
]
}
Pool will reply with
{
"id": 4, # same "id" as in the request
"result": true,
"error": null
}
or report error.
#
Error reporting
Pool response must specify request id in the "id"
field. Errors are reported by setting "result"
to null
and specifying error details in an array of size 3 (code, message, additional info) in the "error"
field.
{
"id": 3,
"result": null,
"error": [
1, # error code
"error msg", # error message
null # additional error information
]
}
01/21/2024 6:07 PM Every coin has its own stratum specification and I changed just very little. Basically we do not have coinbases but mining.notify looks like this:
{
"id": null,
"method": "mining.notify",
"params": [
"jobId", # jobId has to be sent back on submission
"prevHash", # previous hash in block header
"merklePrefix", # prefix of
2, # version
"nbits", # nbits, difficulty target
"ntime", # ntime, timestamp in block header
false # clean? If yes, discard old jobs.
]
}