Stratum is how Bitcoin miners connect with mining pools.
See here for a description of Stratum,
here for a more-detailed overview,
here for another overview, and BIP-310 for extensions.
Also see this BitcoinTalk thread by CK.
Extensions are necessary to support ASIC Boost.
see https://git.0xf0xx0.eth.limo/0xf0xx0/stratumv2 for Stratum V2.
forked from https://github.com/kbnchk/go-Stratum
- 310
- client.reconnect
- client.show_message
- mining.authorize
- mining.configure
- mining.extranonce.subscribe
- mining.notify
- mining.ping
- mining.set_difficulty
- mining.set_extranonce
- mining.set_version_mask
- mining.submit
- mining.subscribe
- mining.suggest_difficulty
- client.get_version
- mining.get_transactions
- mining.suggest_target
use master for now, eventually ill do a 1.0.0 release
go get git.0xf0xx0.eth.limo/0xf0xx0/stratum@mastermsg := []byte(`{"id": 1, "method": "mining.subscribe", "params": ["cpuminer-opt-24.5-x64L"]}`)
request := &stratum.Request{}
request.Unmarshal(msg)
if request.GetMethod() == stratum.MethodMiningSubscribe {
params := &stratum.MiningSubscribeParams{}
params.FromRequest(request)
fmt.Printf("%+v\n", params) // &{UserAgent:cpuminer-opt-24.5-x64L ExtraNonce1:<nil>}
}extranonce1 := stratum.ID(420)
params := stratum.MiningSubscribeParams{
UserAgent: "bitaxe/FTXGOXX",
Extranonce1: &extranonce1,
}
req := params.ToRequest(1)
fmt.Printf("%+v", req) /// &{MessageID:1 Method:mining.subscribe Params:[bitaxe/FTXGOXX 000001a4]}
b, _ := req.Marshal()
fmt.Println(string(b)) /// {"id":1,"method":"mining.subscribe","params":["bitaxe/FTXGOXX","000001a4"]}var conn io.ReadWriter
reader := bufio.NewScanner(conn)
for reader.Scan() {
/// messages are separated by newline
line := reader.Bytes()
var m stratum.Message
if err := m.Unmarshal(line); err != nil {
println(err.Error())
}
switch m.GetMethod() {
case stratum.MethodMiningNotify:
n, ok := m.(*stratum.Notification)
if !ok {
panic("expected notification")
}
params := stratum.MiningNotifyParams{}
if err := params.FromNotification(n); err != nil {
println(err.Error())
continue
}
/// do something
fmt.Printf("%+v\n", params)
case stratum.MethodResponse:
/// response to our request
res, ok := m.(*stratum.Response)
if !ok {
panic("expected response")
}
if res.Error != nil {
/// handle error
}
/// figure out what to do with res.Result
}
}var conn io.ReadWriter
reader := bufio.NewScanner(conn)
for reader.Scan() {
/// messages are separated by newline
line := reader.Bytes()
var m stratum.Request
if err := m.Unmarshal(line); err != nil {
println(err.Error())
}
switch m.GetMethod() {
case stratum.MethodMiningSubscribe:
params := stratum.MiningSubscribeParams{}
if err := params.FromRequest(&m); err != nil {
println(err.Error())
res := m.RespondError(stratum.Error{ /* populated... */ })
b, _ := res.Marshal()
conn.Write(b)
break
}
/// do something
fmt.Printf("%+v\n", params)
}
}customError := stratum.Error{
Code: 420,
Message: "The server blew up.",
Trace: "whgen the, the ehwn, when, when the the when the",
}
b, _ := customError.MarshalJSON()
conn.Write(b)Stratum uses JSON separated by newlines (\n or \r\n). There are three message types: notification, request, and response.
| method | type |
|---|---|
| mining.authorize | request / response |
| mining.configure | request / response |
| mining.extranonce.subscribe | request / response |
| mining.get_transactions | request / response |
| mining.ping | request / response |
| mining.submit | request / response |
| mining.subscribe | request / response |
| mining.suggest_difficulty | notification |
| mining.suggest_target | notification |
| method | type |
|---|---|
| client.get_version | request / response |
| client.reconnect | notification |
| client.show_message | notification |
| mining.notify | notification |
| mining.ping | request / response |
| mining.set_difficulty | notification |
| mining.set_extranonce | notification |
| mining.set_version_mask | notification |
Notification is for methods that don't require a response.
{
method: string, // one of the methods above
params: [json...] // array of json values
}
Request is for methods that require a response.
{
"id": uint or string, // a unique id, typically a hex-encoded number
"method": string, // one of the methods above
"params": [json...] // array of json values
}
Response is the response to requests.
{
"id": integer or string, // a unique id, must be the same as on the request
"result": json, // typically a boolean response
"error": null or [
uint, // error code
string // error message
]
}
The first message that is sent by the client in classic Stratum. For extended Stratum,
mining.configure comes first and then mining.authorize.
Sent by the client after mining.authorize, and initiates mining.
Sent by the client to suggest a new difficulty. It MUST be sent before mining.subscribe to reliably be picked up by the server, otherwise the initial job may be at the server default.
Sent by the server. This happens periodically and when a new block is discovered.
The first message that is sent in extended Stratum. Necessary for ASICBoost. The client sends this to tell the server what extensions it supports.
Sent by the client when a valid share is mined. The version-rolling extension adds an additional versionMask parameter.
Sent by either the server or client at any time. Expects a boolean response.
Sent by the server to notify of a change in version mask. Requires the
version-rolling extension.
Sent by the server after responding to mining.subscribe and every time
the difficulty changes.
- Implement everything to get up to stratum 1.1 support
- figure out what all is in 1.1
- make it more intuitive to handle messages, try to avoid intermediate Messages
- work out all the bugs
- streaming support?