Перейти к основному содержимому

Stratum

Узел включает Stratum-сервер для майнеров. Он слушает на 127.0.0.1 порту 3416, смещённом по сети, как и все остальные порты узла, и работает только при enable_stratum_server = true. Этот ключ по умолчанию равен false в каждой сети, поэтому сгенерированный epic-server.toml всегда требует редактирования перед подключением майнера, включая usernet. См. таблицу портов и epic-server.toml.

Транспорт — сырой TCP с JSON-сообщениями, разделёнными символом новой строки. Каждое сообщение JSON-RPC — одна строка, завершённая символом новой строки, без HTTP-заголовков, путей и кодов состояния.

Методы и коды ошибок​

Обрабатываются методы 5. Всё остальное возвращает -32601.

МетодПараметрыРезультат при успехе
loginlogin, pass, agent, все обязательны"ok". Записывает имя и агент воркера (servers/src/mining/stratumserver.rs:928)
getjobtemplatealgorithmОбъект шаблона задания
submitheight, job_id, nonce, pow"ok", или "blockfound - <block hash>" если шара является блоком
keepaliveнет"ok"
statusнетid, height, difficulty, accepted, rejected, stale для вызывающего воркера

Коды ошибок, которые отправляет сервер:

КодСообщение
-32000Узел синхронизируется — подождите
-32501Шара отклонена из-за низкой сложности
-32502Не удалось проверить решение
-32503Решение отправлено слишком поздно
-32600Некорректный запрос
-32601Метод не найден
32603Внутренняя ошибка

Запрос работы​

getjobtemplate требует параметр algorithm, указывающий, какой из трёх алгоритмов доказательства работы вы намерены майнить. Epic выполняет все три одновременно, поэтому задание привязано к конкретному алгоритму.

algorithm в ответе соответствует тому, что требует политика на данной высоте блока, а не обязательно тому, что вы запросили, поэтому майнеру нужен отдельный воркер для каждого алгоритма. only_randomx ограничивает политику одним алгоритмом в приватной цепочке. См. политику блоков.

Узел возвращает -32000 Node is syncing - Please wait, пока не достигнет peer_min_preferred_outbound_count исходящих пиров. В usernet, где пиры отсутствуют по замыслу, установите этот ключ в 0. См. запуск локальной сети.

Поля шаблона задания (servers/src/mining/stratumserver.rs:176):

ПолеТип
heightu64
job_idu64, индекс версии блока, на основе которого построено задание
pre_powhex-строка сериализованного заголовка включительно до полей перед нонсом
algorithmcuckoo, randomx или progpow
difficultyмассив пар [algorithm_name, minimum_share_difficulty]
block_difficultyмассив пар [algorithm_name, current_block_difficulty]
epochsмассив троек [start_height, end_height, seed_hash], для выбора сида RandomX

Оба списка сложности охватывают Cuckatoo, RandomX и ProgPow, в указанном порядке.

Отправка шар​

submit принимает height, job_id, nonce как число и pow. pow — перечисление с внешним тегом, то есть объект с одним ключом, значение которого является кортежем (servers/src/mining/stratumserver.rs:161):

Алгоритмpow
Cuckoo и Cuckatoo{"Cuckoo": [edge_bits, [nonces]]}, сначала edge bits, затем 42 нонса
RandomX{"RandomX": [32 bytes]}
ProgPow{"ProgPow": [32 bytes]}

Шара, сложность которой превышает block_difficulty, обрабатывается как блок, и результат принимает значение blockfound - <block hash>. Шара, которая превышает только difficulty, засчитывается, и результат равен "ok".

Справочник сообщений​

Сериализация определяется структурами в servers/src/mining/stratumserver.rs.

Запросы​

id — целое число или строка, jsonrpc — "2.0", а params — объект параметров метода или null (servers/src/mining/stratumserver.rs:64).

client -> server, one line each
{"id":"1","jsonrpc":"2.0","method":"getjobtemplate","params":{"algorithm":"randomx"}}
{"id":"2","jsonrpc":"2.0","method":"keepalive","params":null}
{"id":"3","jsonrpc":"2.0","method":"status","params":null}
client -> server, a RandomX share, one line
{"id":"4","jsonrpc":"2.0","method":"submit","params":{
"height":1000001,
"job_id":7,
"nonce":13476209874311234567,
"pow":{"RandomX":[10,27,44,3,255,18,9,72,64,31,88,120,4,17,203,55,
91,6,142,77,38,199,15,60,231,2,113,49,86,170,25,8]}
}}
client -> server, a Cuckatoo share, nonce list abbreviated to 3 of 42, one line
{"id":"5","jsonrpc":"2.0","method":"submit","params":{
"height":1000001,"job_id":7,"nonce":42,
"pow":{"Cuckoo":[31,[1042,20984,31006]]}
}}

Ответы​

Каждый ответ содержит одни и те же четыре ключа и воспроизводит метод, который его породил (servers/src/mining/stratumserver.rs:73). result и error присутствуют оба, один из них null.

server -> client, envelope
{"id": <same as the request>, "jsonrpc": "2.0", "method": <the method called>,
"result": <method result> | null, "error": {"code": <int>, "message": <string>} | null}

result равен "ok" для login и keepalive, строке "blockfound - <hash>" или "ok" для submit, объекту шаблона задания для getjobtemplate и объекту статуса воркера для status.

Просмотр живой сессии​

Один запрос, один ответ, с nc:

# Сначала включите сервер: stratum_mining_config.enable_stratum_server = true
printf '{"id":"1","jsonrpc":"2.0","method":"getjobtemplate","params":{"algorithm":"randomx"}}\n' \
| nc 127.0.0.1 3416

По одному заданию на алгоритм, с ответами в форматированном виде:

examples/python/stratum_probe.py
"""Request one Stratum job per algorithm and print the node's replies.

Standard library only. Run an `epic` node with `enable_stratum_server = true` first.
See https://devdocs.epiccash.com/mining/stratum

Override the defaults for another network:
STRATUM_HOST=127.0.0.1 STRATUM_PORT=23416 python stratum_probe.py
"""

from __future__ import annotations

import json
import os
import socket
from typing import Any

HOST = os.environ.get("STRATUM_HOST", "127.0.0.1")
PORT = int(os.environ.get("STRATUM_PORT", "3416"))
ALGORITHMS = ("randomx", "progpow", "cuckatoo")


def request(stream: Any, request_id: int, method: str, params: Any) -> Any:
"""Send one newline-delimited JSON-RPC request and return the decoded reply.

The transport is raw TCP: one JSON object per line, no HTTP framing.
"""
payload = {"id": str(request_id), "jsonrpc": "2.0", "method": method, "params": params}
stream.write(json.dumps(payload) + "\n")
stream.flush()

line = stream.readline()
if not line:
raise ConnectionError("stratum connection closed before a reply arrived")
return json.loads(line)


def probe(host: str = HOST, port: int = PORT) -> None:
"""Ask for a job template for each algorithm and print what comes back."""
with socket.create_connection((host, port), timeout=15) as sock:
stream = sock.makefile("rw", encoding="utf-8", newline="\n")

for request_id, algorithm in enumerate(ALGORITHMS, start=1):
reply = request(stream, request_id, "getjobtemplate", {"algorithm": algorithm})
print(f"{algorithm}: {json.dumps(reply, indent=2)}")


if __name__ == "__main__":
probe()

Далее​

EpicCash/epic-miner — эталонный майнер. Внешняя поверхность JSON-RPC узла предоставляет ту же работу через HTTP посредством get_block_template, finalize_block_template и submit_block.