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

Что такое Stratum? Язык, на котором говорят майнеры и пулы

Представьте, что вы работаете на заводе и каждые 10 секунд должны идти в кабинет начальника, стучать в дверь и спрашивать: “Есть новая работа?” В большинстве случаев ответ будет: “Нет, делай то же самое.” Вы впустую потратили время на дорогу. А теперь представьте, что так делают 10 000 рабочих одновременно. Именно так выглядел майнинг биткоина до появления протокола Stratum.

В ранние годы биткоин-майнинга (2009-2012) майнеры общались с пулами через протокол под названием getwork. Он был простым и работал — поначалу. Но по мере того как майнинг вырос из увлечения горстки энтузиастов в промышленную индустрию, архитектура getwork стала серьёзным узким местом.

Как работал getwork (и почему это было больно)

Заголовок раздела «Как работал getwork (и почему это было больно)»

Протокол getwork работал поверх HTTP — того же протокола, который ваш браузер использует для загрузки веб-страниц. Каждый раз, когда майнеру нужна была новая работа, он отправлял HTTP-запрос на пул, и пул отвечал заголовком блока для хеширования. Это называется поллинг (polling): майнер постоянно спрашивает сервер “есть что-нибудь новое?”

Вот как выглядел типичный цикл getwork:

  1. Майнер отправляет HTTP GET запрос на пул
  2. Пул отвечает 128-байтным заголовком блока
  3. Майнер перебирает 4-байтное пространство nonce (около 4 миллиардов вариантов)
  4. Если валидная шара не найдена, майнер снова запрашивает работу
  5. Повторять бесконечно

Это создавало несколько проблем:

Расход трафика. Каждый запрос и ответ несли полные HTTP-заголовки — куки, content-type, информацию о соединении — добавляя сотни байтов накладных расходов к тому, что должно быть крошечным обменом данными. Когда тысячи майнеров опрашивают пул каждые несколько секунд, эти накладные расходы складываются в серьёзные цифры.

Исчерпание пространства nonce. 4-байтный nonce даёт примерно 4,3 миллиарда хешей для перебора. Звучит как много, но уже в 2011 году GPU исчерпывали это пространство менее чем за секунду. Майнерам приходилось запрашивать новую работу несколько раз в секунду, забрасывая сервер пула HTTP-запросами.

Отсутствие серверных уведомлений. Это главная проблема. Когда в сети Биткоин находился новый блок, майнерам нужно было немедленно прекратить текущую работу (она стала устаревшей). Но с getwork у пула не было способа сообщить об этом майнерам. Приходилось ждать, пока каждый майнер снова отправит запрос. Эти потерянные секунды означали потраченное впустую электричество и упущенный доход.

Кошмар масштабируемости. HTTP — тяжёлый протокол. Каждый запрос открывает соединение, отправляет заголовки, получает ответ и закрывает соединение (или поддерживает его с дополнительными накладными расходами). Пулы с трудом справлялись с десятками тысяч опрашивающих клиентов.

Появление Stratum: протокол, который всё исправил

Заголовок раздела «Появление Stratum: протокол, который всё исправил»

В 2012 году Марек Палатинус (известный в сети как “slush”) — тот самый человек, который создал первый в мире майнинг-пул Slush Pool (сейчас Braiins Pool) — разработал протокол Stratum. Он понимал проблемы изнутри, потому что сталкивался с ними ежедневно, управляя пулом, обслуживающим тысячи майнеров.

Философия дизайна Stratum была простой: перестать опрашивать, начать уведомлять.

1. Чистый TCP вместо HTTP

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

Майнер подключается к пулу один раз, и это TCP-соединение остаётся открытым на протяжении всей сессии майнинга. Никаких повторных рукопожатий, никаких HTTP-заголовков, никаких лишних расходов.

2. JSON-RPC для сообщений

Хотя транспортный уровень — это чистый TCP, сами сообщения форматируются как JSON-RPC (JavaScript Object Notation - Remote Procedure Call). Это легковесный стандарт для кодирования вызовов методов и ответов. Каждое сообщение — это одна строка JSON-текста, завершающаяся символом новой строки (\n).

Вот как выглядит сообщение Stratum:

{"id": 1, "method": "mining.subscribe", "params": ["my-miner/1.0"]}

Компактно, читаемо человеком и легко парсится. Сравните это с раздутым HTTP-запросом, который требовал getwork.

3. Push-архитектура

Это главное нововведение. Вместо того чтобы майнеры спрашивали “есть что-нибудь новое?”, пул сам отправляет новую работу майнерам, как только она появляется. Когда в сети найден новый блок, пул немедленно отправляет уведомление каждому подключённому майнеру: “Бросай текущую работу, вот новое задание.”

Возвращаясь к нашей аналогии с заводом: Stratum — это когда начальник вызывает вас по громкой связи, когда есть новая работа, вместо того чтобы вы каждые 10 секунд ходили к нему в кабинет спрашивать.

4. Построчный протокол

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

{"id":1,"method":"mining.subscribe","params":["miner/1.0"]}\n
{"id":2,"method":"mining.authorize","params":["worker1","pass"]}\n

Вот упрощённая схема того, что происходит при подключении майнера к пулу через Stratum:

Майнер Пул
| |
|--- TCP-подключение --------->|
| |
|--- mining.subscribe -------->|
|<-- результат подписки -------|
| |
|--- mining.authorize -------->|
|<-- результат авторизации ----|
| |
|<-- mining.set_difficulty ----|
|<-- mining.notify (задание) --|
| |
| [майнер начинает хешировать]
| |
|--- mining.submit (шара) ---->|
|<-- результат отправки -------|
| |
|<-- mining.notify (задание) --|
| [цикл продолжается...] |

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

Давайте подкрепим улучшения цифрами:

АспектgetworkStratum
ТранспортHTTP (тяжёлые заголовки)Чистый TCP (минимум накладных расходов)
СоединениеНовый запрос каждый разОдно постоянное соединение
Доставка работыМайнер опрашивает (pull)Пул уведомляет (push)
Уведомление о новом блокеЖдать следующего опросаМгновенный push
Пространство nonce4 байта (ограничено)Расширено через extraNonce
Трафик на задание~1 КБ+ (накладные расходы HTTP)~200-300 байт
Формат сообщенийТекст поверх HTTPПострочный JSON поверх TCP

Помните проблему исчерпания nonce? Stratum решил её элегантно. Вместо одного 4-байтного nonce в заголовке блока, Stratum ввёл концепцию extraNonce — дополнительное пространство nonce, встроенное в coinbase-транзакцию.

Пул назначает каждому майнеру уникальное значение extraNonce1 и сообщает, сколько байтов extraNonce2 майнер может перебирать. Вместе с 4-байтным nonce в заголовке это даёт каждому майнеру огромное пространство для поиска. Майнер с 4-байтным extraNonce2 имеет 4,3 миллиарда умножить на 4,3 миллиарда вариантов, прежде чем ему понадобится новое задание — гораздо больше, чем любой ASIC сможет перебрать до прихода следующего задания.

Каждое сообщение Stratum следует формату JSON-RPC 2.0 (хотя технически Stratum использует несколько упрощённую версию). Существует три типа сообщений:

{
"id": 1,
"method": "mining.subscribe",
"params": ["user-agent/version"]
}
  • id: Уникальный номер для сопоставления ответов с запросами. Отправитель выбирает любое целое число.
  • method: Вызываемая процедура (как имя функции).
  • params: Массив аргументов для этого метода.
{
"id": 1,
"result": [/* данные при успехе */],
"error": null
}
  • id: Совпадает с запросом, который вызвал этот ответ.
  • result: Возвращаемое значение при успехе (null при ошибке).
  • error: Детали ошибки, если что-то пошло не так (null при успехе).
{
"id": null,
"method": "mining.notify",
"params": [/* данные задания */]
}
  • id: Всегда null для уведомлений — отправитель не ожидает ответа.
  • Это сообщения типа “отправил и забыл”, обычно от пула к майнеру.

К 2013 году практически каждый майнинг-пул перешёл на Stratum. Это произошло не благодаря какому-то отраслевому комитету или формальному процессу стандартизации. Он победил по той же причине, по которой побеждает большинство хороших протоколов: он был простым, эффективным и решал реальные проблемы.

Несколько факторов закрепили его доминирование:

  1. Открытая спецификация. Марек опубликовал спецификацию протокола в открытом доступе, и любой мог её реализовать. Никакого лицензирования, никаких ограничений.

  2. Простота реализации. Парсинг построчного JSON поверх TCP — это то, что любой программист может сделать за несколько часов. ПО для пулов и прошивки майнеров быстро перешли на него.

  3. Проверен в боевых условиях. Slush Pool был одним из крупнейших пулов, поэтому протокол был доказан под реальной нагрузкой ещё до того, как другие начали его внедрять.

  4. Совместимость с развивающимся оборудованием. По мере перехода майнеров с CPU на GPU, с GPU на FPGA, с FPGA на ASIC, архитектура Stratum (особенно extraNonce) элегантно справлялась с растущими хешрейтами.

  5. Низкий расход трафика. Для майнинг-ферм в удалённых местах с ограниченным интернетом эффективность Stratum была значительным преимуществом перед getwork.

Ни один протокол не идеален, и после более чем десяти лет службы ограничения Stratum V1 стали очевидны:

Отсутствие шифрования. Весь трафик Stratum V1 — это открытый JSON-текст поверх TCP. Любой, кто может наблюдать сетевой трафик (провайдеры, сетевые администраторы, государственные органы), видит, что именно вы майните, имена ваших воркеров и хешрейт. Это проблема приватности и безопасности.

Пул контролирует шаблон блока. В Stratum V1 пул решает, какие транзакции попадут в блок. Майнеры просто хешируют то, что пул им выдал. Это даёт пулам непропорциональное влияние на отбор транзакций, что не лучшим образом сказывается на децентрализации Биткоина.

Накладные расходы JSON. Хотя это намного лучше HTTP, JSON всё ещё текстовый формат. Ту же информацию можно было бы закодировать в бинарном виде, используя гораздо меньше байтов. Для крупных майнинг-ферм с тысячами ASIC эти накладные расходы существенны.

Нет аутентификации пула. У майнера нет криптографического способа проверить, что он действительно общается с тем пулом, к которому собирался подключиться. Атаки “человек посередине” (MITM) могут перенаправить хешрейт, и ни майнер, ни пул об этом не узнают.

Эти проблемы привели к разработке Stratum V2, который мы рассмотрим в заключительной статье этой серии.

Протокол Stratum трансформировал коммуникацию в биткоин-майнинге из неэффективной HTTP-системы на основе поллинга в оптимизированный push-протокол поверх TCP. Созданный в 2012 году Мареком Палатинусом, он решил критические проблемы расхода трафика, исчерпания пространства nonce и задержек в уведомлениях о новых блоках, которые мучили предшествующий протокол getwork.

По своей сути Stratum красиво прост: постоянное TCP-соединение, несущее построчные JSON-RPC сообщения, где пул отправляет работу майнерам, а майнеры отправляют шары обратно. Эта простота — именно та причина, по которой он оставался отраслевым стандартом более десяти лет.

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