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

Жизненный цикл соединения: от TCP-рукопожатия до стабильного майнинга

Когда ASIC-майнер включается и подключается к майнинг-пулу, он проходит через точную последовательность шагов, прежде чем начнёт зарабатывать вам деньги. Представьте это как первый день на новой работе: сначала вы приходите в здание (TCP-подключение), затем отмечаетесь на ресепшене (subscribe), показываете пропуск (authorize), получаете информацию о сложности заданий (set_difficulty), получаете первое задание (notify), и затем приступаете к работе (хеширование и отправка).

Эта статья проведёт вас через каждый шаг этой последовательности с реальными JSON-RPC сообщениями, которые вы увидите на проводе.

Вот полный жизненный цикл — от холодного старта до стабильного майнинга:

МАЙНЕР ПУЛ
| |
| Шаг 1: TCP-подключение |
|-------- SYN --------------------------------->|
|<------- SYN-ACK -----------------------------|
|-------- ACK --------------------------------->|
| |
| Шаг 2 (опционально): mining.configure |
| (согласование version rolling) |
|-------- mining.configure -------------------->|
|<------- результат configure ------------------|
| |
| Шаг 3: mining.subscribe |
| (регистрация, получение extraNonce) |
|-------- mining.subscribe -------------------->|
|<------- результат subscribe ------------------|
| |
| Шаг 4: mining.authorize |
| (аутентификация воркера) |
|-------- mining.authorize -------------------->|
|<------- результат authorize ------------------|
| |
| Шаг 5: Пул отправляет начальные параметры |
|<------- mining.set_difficulty ----------------|
|<------- mining.notify (первое задание) -------|
| |
| Шаг 6: Стабильный цикл майнинга |
| [майнер хеширует... находит шару] |
|-------- mining.submit ----------------------->|
|<------- результат submit ---------------------|
| |
| [пул нашёл новый блок или меняет сложность] |
|<------- mining.notify (новое задание) --------|
|<------- mining.set_difficulty (коррекция) ----|
| |
| [цикл продолжается бесконечно] |
| |

Давайте разберём каждый шаг подробно.

Прежде чем начнётся обмен сообщениями Stratum, майнер должен установить TCP-соединение с пулом. Это стандартная сетевая процедура — трёхстороннее рукопожатие (SYN, SYN-ACK, ACK), которое создаёт надёжный двунаправленный канал связи.

Майнер подключается к определённому хосту и порту, указанному пулом. Например:

  • stratum+tcp://pool.example.com:3333 — стандартное нешифрованное соединение
  • stratum+ssl://pool.example.com:3334 — шифрование TLS (некоторые пулы поддерживают)

Номер порта важен. Многие пулы используют разные порты для разных уровней сложности или функций:

ПортТипичное использование
3333Стандартная сложность (ASIC)
3334Высокая сложность
3335NiceHash или прокси-соединения
25Низкая сложность (старые/маломощные устройства)

После установки TCP-соединения майнер и пул могут начать обмен JSON-RPC сообщениями. Каждое сообщение — это одна строка JSON, завершающаяся символом \n.

Современные ASIC, поддерживающие version rolling (техника, связанная с AsicBoost), отправляют сообщение mining.configure перед подпиской. Оно согласовывает, какие расширения протокола поддерживают и майнер, и пул.

Майнер отправляет:

{
"id": 1,
"method": "mining.configure",
"params": [
["version-rolling"],
{"version-rolling.mask": "1fffe000", "version-rolling.min-bit-count": 2}
]
}

Пул отвечает:

{
"id": 1,
"result": {
"version-rolling": true,
"version-rolling.mask": "1fffe000"
},
"error": null
}

version-rolling.mask указывает майнеру, какие биты поля версии блока ему разрешено изменять. Это даёт ASIC дополнительное пространство для перебора без необходимости изменять сам nonce или extraNonce. Мы рассмотрим это подробнее в статье о mining.subscribe.

Здесь майнер регистрируется на пуле. Представьте это как заселение в гостиницу — вам дают номер комнаты (идентификатор сессии) и ключ (extraNonce1).

Майнер отправляет:

{
"id": 2,
"method": "mining.subscribe",
"params": ["bmminer/2.0.0", null]
}

Параметры:

  1. Строка пользовательского агента — идентифицирует ПО для майнинга и его версию
  2. ID предыдущей подпискиnull для нового соединения, или ID сессии при попытке возобновления

Пул отвечает:

{
"id": 2,
"result": [
[
["mining.set_difficulty", "deadbeef00000000"],
["mining.notify", "deadbeef00000001"]
],
"a1f1c230",
4
],
"error": null
}

Ответ содержит три критически важных элемента:

  1. Пары подписок — сообщают майнеру, на какие уведомления он подписан (set_difficulty и notify), каждое со своим ID подписки
  2. extraNonce1 — hex-строка ("a1f1c230"), которая уникально идентифицирует сессию этого майнера. Каждая шара, отправленная этим майнером, будет содержать это значение.
  3. Размер extraNonce2 — количество байтов (4 в этом примере), которые майнер может использовать для собственного перебора

extraNonce1 назначается пулом и не должен изменяться майнером. Пул использует его для различения шар от разных майнеров.

Теперь майнер представляется — кто этот воркер и на какой аккаунт начислять награду за майнинг?

Майнер отправляет:

{
"id": 3,
"method": "mining.authorize",
"params": ["username.worker1", "x"]
}

Параметры:

  1. Имя воркера — обычно в формате аккаунт.воркер или адрес_кошелька.воркер
  2. Пароль — обычно игнорируется большинством пулов (часто просто "x" или ""), хотя некоторые пулы используют его для настройки

Пул отвечает (успех):

{
"id": 3,
"result": true,
"error": null
}

Пул отвечает (неудача):

{
"id": 3,
"result": null,
"error": [24, "Unauthorized worker", null]
}

Если авторизация не пройдена, майнер не сможет отправлять шары. Большинство реализаций закроют соединение и попробуют снова с правильными учётными данными.

Как только майнер подписан и авторизован, пул немедленно отправляет два критически важных элемента:

{
"id": null,
"method": "mining.set_difficulty",
"params": [512]
}

Это сообщает майнеру текущую сложность шары. Майнер должен находить хеши, которые ниже таргета, соответствующего этому значению сложности. Обратите внимание: id равен null — это уведомление, а не запрос.

{
"id": null,
"method": "mining.notify",
"params": [
"bf",
"0000000000000000000354da8e026f48a0467f9d5290a7e30b86e1a80213e5fe",
"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4b03a8960cfabe6d6d",
"0100000001000000001976a914cb72e7463c3544121c5f37a8f3296c16c6a1289388ac00000000",
[
"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"d4735e3a265e16eee03f59718b9b5d03019c07d8b6c51f90da3a666eec13ab35"
],
"20000000",
"1705ae3a",
"64a5f8c2",
true
]
}

Это собственно работа, которую должен выполнить майнер. Мы детально разберём каждое поле mining.notify в следующей статье, а пока главное: это сообщение содержит всё, что нужно майнеру для построения заголовков блоков и начала хеширования.

Последний параметр (true) — это флаг clean_jobs. Когда он true, это означает: “Бросай всю предыдущую работу и переключайся на это немедленно.” Для первого задания он всегда true.

Теперь майнер полностью работоспособен. Он входит в цикл, который продолжается, пока соединение живо:

  1. Хеширование — Майнер строит заголовки блоков, используя данные из mining.notify, и перебирает пространство nonce, ища хеши, удовлетворяющие целевой сложности.

  2. Отправка шар — Когда майнер находит хеш ниже таргета, он отправляет mining.submit:

{
"id": 4,
"method": "mining.submit",
"params": [
"username.worker1",
"bf",
"00000001",
"64a5f8c2",
"1a2b3c4d"
]
}

Пул отвечает успехом или ошибкой:

{"id": 4, "result": true, "error": null}
  1. Получение новых заданий — Пул периодически отправляет новые сообщения mining.notify. Это может происходить по нескольким причинам:

    • В сети найден новый блок (clean_jobs = true)
    • Пул хочет обновить набор транзакций в шаблоне блока (clean_jobs = false)
    • Прошло достаточно времени, и метку времени пора обновить
  2. Корректировка сложности — Пул отслеживает частоту отправки шар и корректирует сложность через mining.set_difficulty. Если вы отправляете шары слишком часто, сложность растёт. Слишком редко — снижается.

Этот цикл продолжается бесконечно — часами, днями, неделями — пока что-нибудь не разорвёт соединение.

Соединения рвутся. Это факт жизни. Скачки напряжения, перезагрузки роутера, техобслуживание пула, сбои провайдера — существует множество причин, по которым TCP-соединение может оборваться. Вот что делает правильно работающий майнер:

Майнер обнаруживает разрыв одним из нескольких способов:

  • Получен TCP reset или FIN от пула
  • Запись в сокет не удалась (broken pipe)
  • Данные не получены слишком долго (собственный таймаут keepalive майнера)

Некоторые майнеры периодически отправляют сообщения mining.ping (или любой фиктивный запрос) для обнаружения мёртвых соединений. Если пул не отвечает в течение таймаута, соединение считается разорванным.

Соединение разорвано
|
v
Ожидание (период отсрочки)
|
v
Попытка основного пула ---> Успех? ---> Повторная подписка + авторизация
| |
| Неудача v
v Возобновление майнинга
Попытка резервного пула с новым extraNonce1 и заданиями
|
| Неудача
v
Увеличение отсрочки
(экспоненциально: 1с, 2с, 4с, 8с... до 60с)
|
v
Повторная попытка основного пула
[цикл]

Ключевые моменты переподключения:

  1. Повторная подписка обязательна. После переподключения майнер должен снова пройти mining.subscribe и mining.authorize. Пул может назначить другой extraNonce1.

  2. Старая работа недействительна. Любые шары, над которыми майнер работал в предыдущей сессии, бесполезны. Майнер должен дождаться новых сообщений mining.notify.

  3. Экспоненциальная отсрочка. Хороший майнер не забрасывает пул попытками переподключения. Он ждёт 1 секунду, затем 2, затем 4, затем 8 и так далее, с ограничением около 60 секунд. Это предотвращает перегрузку пула при сбое.

  4. Резервные пулы. Большинство прошивок позволяют настроить несколько адресов пулов. Если основной пул недоступен, майнер переключается на вторичный, затем на третичный. Он периодически проверяет, не вернулся ли основной пул.

Майнер пытается возобновить:

{
"id": 1,
"method": "mining.subscribe",
"params": ["bmminer/2.0.0", "previous_subscription_id_here"]
}

Если пул ещё хранит сессию в памяти, он может вернуть тот же extraNonce1, позволяя майнеру продолжить без потерь. Если сессия истекла или пул не поддерживает возобновление, он просто назначает новую сессию.

Хронометраж: как быстро всё это происходит?

Заголовок раздела «Хронометраж: как быстро всё это происходит?»

При типичном соединении всё рукопожатие — от TCP-подключения до получения первого задания — занимает значительно менее одной секунды. Вот реалистичная хронология:

ШагВремя от начала
TCP-рукопожатие (SYN/SYN-ACK/ACK)~20-50 мс
mining.configure (если используется)~50-100 мс
mining.subscribe + ответ~80-150 мс
mining.authorize + ответ~100-200 мс
Получение mining.set_difficulty~120-220 мс
Получение mining.notify~130-230 мс
Майнер начинает хеширование~150-250 мс

Эти числа предполагают стабильное интернет-соединение с задержкой ~20 мс до пула. На практике большинство ASIC начинают хешировать в течение 200-300 миллисекунд после подключения. Для машины, работающей 24/7, эти затраты на запуск пренебрежимо малы.

Чтобы свести всё воедино, вот как могут выглядеть реальные байты на проводе при полной настройке соединения. Каждая строка — одно JSON-RPC сообщение (разделённое символами новой строки):

Майнер —> Пул:

{"id":1,"method":"mining.configure","params":[["version-rolling"],{"version-rolling.mask":"1fffe000","version-rolling.min-bit-count":2}]}

Пул —> Майнер:

{"id":1,"result":{"version-rolling":true,"version-rolling.mask":"1fffe000"},"error":null}

Майнер —> Пул:

{"id":2,"method":"mining.subscribe","params":["bmminer/2.0.0",null]}

Пул —> Майнер:

{"id":2,"result":[[["mining.set_difficulty","1"],["mining.notify","1"]],"abcd1234",4],"error":null}

Майнер —> Пул:

{"id":3,"method":"mining.authorize","params":["myaccount.worker1","x"]}

Пул —> Майнер:

{"id":3,"result":true,"error":null}

Пул —> Майнер:

{"id":null,"method":"mining.set_difficulty","params":[512]}

Пул —> Майнер:

{"id":null,"method":"mining.notify","params":["job1","prevhash...","cb1...","cb2...","merkle...","20000000","1a0ffff0","64b1c3a5",true]}

В этот момент майнер имеет всё необходимое и начинает хеширование. Первая отправка шары может произойти через секунды или минуты, в зависимости от хешрейта майнера и сложности шары.

Интересная особенность Stratum — одно TCP-соединение может обслуживать нескольких воркеров. Это часто используется майнинг-прокси — программным обеспечением, которое стоит между фермой ASIC и пулом. Прокси поддерживает одно соединение с пулом, но управляет десятками или сотнями ASIC локально.

Процесс выглядит так:

{"id":3,"method":"mining.authorize","params":["account.worker1","x"]}
{"id":4,"method":"mining.authorize","params":["account.worker2","x"]}
{"id":5,"method":"mining.authorize","params":["account.worker3","x"]}

Каждый воркер авторизуется независимо, и шары, отправленные через mining.submit, указывают, какой воркер их нашёл. Пул отслеживает хешрейт и заработок по каждому воркеру.

Вот проблемы, с которыми вы можете столкнуться, и что они означают:

“Connection refused” — Сервер пула не слушает на этом порту. Проверьте имя хоста, порт и то, что пул действительно работает.

“Connection timeout” — Ваша сеть не может добраться до пула. Может быть файрвол, проблема провайдера или перегрузка пула. Попробуйте другой адрес или порт.

Ошибка авторизации — Вы подключаетесь нормально, но пул отклоняет имя воркера. Перепроверьте имя аккаунта, адрес кошелька или формат воркера. Некоторые пулы требуют предварительного создания воркеров в веб-панели.

Немедленное отключение после subscribe — Это иногда происходит при подключении к неправильному порту (например, SSL-порт без TLS или наоборот).

Устаревшие шары после переподключения — Если вы переподключитесь и немедленно отправите шары из старой сессии, пул их отклонит. Всегда дожидайтесь свежих сообщений mining.notify после переподключения.

Жизненный цикл соединения Stratum — это чётко определённая последовательность:

  1. TCP-подключение к хосту и порту пула
  2. mining.configure (опционально) для согласования расширений протокола, таких как version rolling
  3. mining.subscribe для регистрации и получения extraNonce1 и размера extraNonce2
  4. mining.authorize для аутентификации воркера
  5. mining.set_difficulty и mining.notify от пула для настройки начальной работы
  6. Стабильный цикл: получение заданий, хеширование, отправка шар, корректировка сложности

При разрыве соединения майнер переподключается с экспоненциальной отсрочкой и проходит всё рукопожатие заново. Некоторые пулы поддерживают возобновление сессии для более быстрого восстановления.

В следующей статье мы детально разберём mining.subscribe и mining.authorize — рассмотрим каждое поле, каждый крайний случай и то, как на самом деле работает назначение extraNonce.