Перевод статьи, опубликованной в блоге Freedom to Tinker.
11 марта 2013 года Биткоин пережил технический кризис. Версии 0.7 и 0.8 программного обеспечения отличались друг от друга в поведении из-за ошибки, что привело к разделению цепочки блоков. Учитывая, насколько катастрофичным может быть хардфорк, кризис был быстро разрешен с удивительно малым ущербом благодаря исключительной компетентности ответственных разработчиков. Это событие позволяет нам заглянуть во внутреннее устройство Биткоина. В этой статье я проведу анализ тех драматических минут и сформулирую множество удивительных выводов. Краткое описание этого события смотрите здесь.
Прежде всего, этот инцидент показывает необходимость эффективного механизма консенсуса для людей в экосистеме Биткоина. Хронология событий выглядит следующим образом: потребовалось около часа после начала форка, чтобы накопилось достаточно доказательств того, что форк произошел. Как только это стало понятно, события развивались с поразительной скоростью и эффективностью. Оптимальный вариант действий (и, оглядываясь назад, единственный, который позволил избежать серьезных рисков для системы) был впервые предложен и обоснован через 16 минут, а разработчики достигли консенсуса по нему всего через 20-25 минут. Вскоре после этого — едва ли через час после обнаружения форка — антикризисные действия были эффективно и успешно завершены. Еще несколько часов ушло на то, чтобы исправить форк в соответствии с начатым разработчиками курсом действий, но исход уже не вызывал сомнений.
Что еще более удивительно, он также демонстрирует эффективность сильного центрального руководства. Потому что разумное решение проблемы форка — как и то, которое было заложено в само программное обеспечение — заключалось в том, чтобы побудить майнеров, использующих старые версии, обновиться. Как оказалось, правильная реакция была прямо противоположной. Задержка даже на несколько часов в принятии решения о понижении версии была бы очень рискованной, как я покажу в этой статье, и имела бы потенциально разрушительные последствия. Без централизованной координации разработчиков Bitcoin Core и большого доверия к ним со стороны сообщества невозможно представить себе, что принятие этого неинтуитивного решения могло бы быть успешно осуществлено.
Кроме того, еще два аспекта централизации оказались очень полезными, хотя, возможно, и не столь необходимыми. Первый — это возможность у нескольких разработчиков, обладающих криптографическим ключом, транслировать каждому клиенту сообщения с предупреждениями, которые в данном случае использовались для того, чтобы призвать пользователей к понижению версии. Второе — это тот факт, что оператор BTC Guild, крупного майнингового пула на тот момент, смог в одиночку сместить баланс майнинговых сил в сторону старой ветки путем понижения версии. Если бы не это, то возникла бы “проблема координации” среди майнеров, и мы можем представить, как каждый из них колеблется, ожидая, пока кто-то другой сделает первый шаг.
Поскольку большая часть обсуждения и принятия решений происходила на IRC-канале #bitcoin-dev, он остался в открытом доступе и позволяет взглянуть на лидирующую роль разработчиков Core и процесс консенсуса. Консенсус происходил с удивительной скоростью, в данном случае быстрее, чем происходит консенсус в самой сети Биткоин. Два уровня консенсуса тесно связаны между собой.
Теперь давайте погрузимся в подробный анализ форка и реакции на него. Я аннотировал расшифровку отдельных ключевых событий из лога IRC-канала той роковой ночи. Я внес небольшие правки, чтобы сделать журнал более удобным для чтения — в основном заменив ники известных членов сообщества на их настоящие имена, поскольку их личности важны для обсуждения.
Первые признаки проблемы #
Первые признаки того, что что-то не так, появились у майнера с ником thermoman, а также у оператора голландской биржи Яуке Хофмана, которые сообщили о странном поведении своих Биткоин-клиентов. Разработчик ядра Биткоина Питер Вюлле помогает им разобраться с неполадками, но на данный момент все полагают, что это локальные проблемы у этих двух пользователей, а не что-то в сети. Но примерно в 23:00 замечается странное поведение ряда других сервисов (blockchain.info, blockexplorer.com и IRC-бот, сообщающий о состоянии сети), что делает очевидным, что в сети что-то не так. Люк Дашер, авторитетный разработчик, заявляет невероятное:
Так что??? Ура случайному хардфорку? :x
— 23:06, Люк Дашер
Вот дерьмо.
— 23:06, Яуке Хофман
В течение следующих нескольких минут участники убеждаются в том, что существует форк и что узлы, на которых работают версии 0.8 и 0.7, находятся по разные стороны. Дальше события развиваются стремительно. Спустя всего пять минут Марк Карпелес, основатель Mt. Gox, предпринимает первые меры по снижению ущерба:
Я отключил синхронизацию блоков Биткоина, пока мы не разберемся с этим.
— 23:11, Марк Карпелес
Я пытаюсь связаться с операторами майнинговых пулов.
— 23:13, Люк Дашер
На данный момент совершенно очевидно, что лучшее краткосрочное решение - это перевести всех на одну сторону форка. Но на какую?
Вверх или вниз? Критически важное решение #
В 23:18 Питер Вюлле отправляет сообщение в список рассылки bitcoin-dev, информируя о проблеме. Но он еще не до конца понял природу форка, заявив: “Мы рискуем получить (несколько) форк-цепочек с меньшими блоками”, и предлагает в качестве решения обновление клиентов. Это прискорбно, но это правильное решение, учитывая его понимание форка. Это письмо останется неисправленным в течение 45 минут и, пожалуй, является единственной небольшой ошибкой в реакции разработчиков.
По крайней мере 38% хэшрейта сейчас на 0.8, и эти 38% в зоне доступа.
— 23:21, Люк Дашер
Дашер, кажется, предполагает, что понижение версии с 0.8 до 0.7 лучше, потому что операторы недавно обновленных узлов с большей вероятностью будут доступны разработчикам, чтобы убедить их понизить версию. Это заманчивый аргумент. Действительно, когда я описываю развилку в аудитории и спрашиваю своих студентов, почему разработчики выбрали понижение версии, а не повышение, они всегда приходят именно к такому объяснению. Когда я подталкиваю их к более серьезным размышлениям, несколько человек приходят к правильному ответу, на который сразу же указывает Дашер:
Цепочка 0.8 длиннее, да? Так что большинство вычислительной мощности — это 0.8….
— 23:22, Гэвин Андресен
Но форк 0.8 не совместим с предыдущими версиями, чтобы быть принятым всеми остальными
— 23:22, Люк Дашер
Вот именно! Поведение двух версий не является симметричным. Обновление означает, что форк будет существовать практически бесконечно, в то время как понижение версии приведет к его относительно быстрому завершению.
Ведущий разработчик Гэвин Андресен все еще протестует, но Вюлле также принимает аргументы Дашера:
Первое правило Биткоина: большинство вычислительной мощности побеждает.
— 23:23, Гэвин Андресен
Если мы перейдем на 0.8, будет хардфорк.
— 23:23, Люк Дашер
Последствия форка — слишком большие блоки, но если мы снова попросим майнеров временно перейти на цепочку с меньшими блоками, мы должны скоро прийти к единой цепочке с большинством майнеров на маленьких блоках, нет никакого риска.
— 23:23, Питер Вюлле
Таким образом, это либо 1) потеря 6 блоков, либо 2) бесполезный хардфорк.
— 23:24, Люк Дашер
Мы потеряем больше, чем 6
— 23:25, оператор майнинг-пула BTC Guild
BTC Guild был крупным пулом на тот момент, и его оператор случайно оказался онлайн. Он прав — в ветке 0.8 на тот момент было 6 блоков, но она росла гораздо быстрее ветки 0.7 и продолжала расти, пока позже постепенно не догнала ее. В итоге 24 блока будут потеряны. BTC Guild окажется ключевым игроком, как мы скоро увидим.
Более подробное объяснение того, почему понижение версии является правильным подходом:
Все старые майнеры будут придерживаться своей собственной цепочки, независимо от того, какая майнинговая мощность стоит за второй.
— 23:25, Питер Вюлле
И чем раньше мы определимся с номером 1, тем меньше они потеряют.
— 23:25, Люк Дашер
Даже при 90% мощности майнинга в 0.8 все мерчанты на старом клиенте будут уязвимы.
— 23:26, Питер Вюлле
Если мы сделаем хардфорк, все поставщики услуг, использующие Биткоин, окажутся в чрезвычайной ситуации.
— 23:26, Люк Дашер
И мы не можем заставить всех пользователей Биткоина в мире мгновенно перейти на 0.8, так что нет, нам нужно откатиться к цепочке 0.7.
— 23:30, Питер Вюлле
Ахтунг! #
Многие пользователи Биткоина не знают о том, что в Биткоине у нескольких разработчиков существует централизованная возможность рассылать сообщения о тревоге 1. Эта возможность не только существует, но и приобретает решающее значение, как отмечают разработчик Core Джефф Гарзик и другой пользователь:
Тревога определенно необходима.
— 23:31, Джефф Гарзик
Если это не сценарий сигнала тревоги, то я не знаю, о чем идет речь, где это? :)
— 23:31, jrmithdobbs
Немного юмора от оператора ozcoin, еще одного майнингового пула:
На ozcoin даже не будут смотреть в течение часа или около того. Никого нет дома, а мне нужно отвезти детей в школу.
— 23:31, Graet
Ситуация не терпит отлагательств (чем больше клиентов обновится, тем сложнее будет убедить всех понизить версию):
Клиенты версии 0.7 уже отображают большое страшное предупреждение. Предупреждение: “Отображаемые транзакции могут быть недействительными! Вам может потребоваться обновление, либо другие узлы нуждаются в обновлении”. К сожалению, я подозреваю, что это предупреждение заставит людей обновить версию.
— 23:32, phantomcircuit
Другие сложности, связанные с нестандартным поведением программного обеспечения некоторых майнеров:
О, черт. В любом случае, пожалуйста, держите нас в курсе, какое изменение кода было сделано для решения проблемы. Наша кастомная нода ведет себя как версия 0.8.
— 23:35, lianj
Гэвин Андресен и Джефф Гарзик все еще не уверены (похоже, они думают о том, как заставить узлы версии 0.8 перейти на другую ветку, а не о более грубом решении — попросить майнеров понизить версию клиента):
И как сказать bitcoind “майни на $этой старой цепочке”?
— 23:34, Джефф Гарзик
Именно. Даже если мы хотим откатиться к цепочке, совместимой с 0.7, я не вижу простого способа сделать это.
— 23:35, Гэвин Андресен
А это свидетельствует о том, что разработчики имеют прямые каналы связи с операторами пулов, что является еще одним преимуществом централизованной координации:
Если на то пошло, Джош (EclipseMC) должен лететь на самолете через 20 минут, так что ему нужно решить все до этого момента :/
— 23:38, Люк Дашер
Со временем решение становится все сложнее, как показывает пример нового пользователя, зашедшего на канал.
Так в чем же проблема? Я получил предупреждение о необходимости обновления. Поэтому я обновился.
— 23:39, senseless
Гэвин Андресен, известный своей осторожностью, поднимает возможную проблему:
Если мы вернемся к 0.7, то рискуем, что какой-нибудь другой блок вызовет такое же состояние.
— 23:40, Гэвин Андресен
К счастью, как отметили другие, беспокоиться не о чем — как только большинство вычислительной мощности перейдет на 0.7, другие блоки с таким же состоянием будут безобидными одноблочными форками, а не хардфорками.
Оператор BTC Guild предлагает в принципе прекратить форк:
Я могу в одиночку вернуть к 0.7 большинство хэшрейта. Мне просто нужно подтверждение того, что это то, что нужно сделать.
— 23:43, BTC Guild
По моему мнению, так и следует поступить, но сначала нужно прийти к консенсусу.
— 23:44, Питер Вюлле
Вот вам и децентрализация! Тот факт, что BTC Guild смогла склонить чашу весов, в этом случае имеет решающее значение. На тот момент распределение хэшрейта было примерно 2/3 против 1/3 в пользу ветви 0.8, а BTC Guild контролировала где-то 20-30 % от общего хэшрейта. Переключившись, BTC Guild теряет результаты работы, которую они проделали над 0.8 с момента начала форка. С другой стороны, они более или менее уверены в том, что ветвь 0.7 победит и форк закончится, так что, по крайней мере, их майнинговые мощности после понижения не будут потрачены впустую.
Если бы мощность майнинга была распределена между тысячами мелких независимых майнеров, далеко не очевидно, что их координация вообще была бы возможна. Скорее всего, каждый майнер в ветке 0.8 ждал бы, пока ветка 0.7 наберет большинство хэшрейта или, по крайней мере, начнет двигаться явно в этом направлении, прежде чем принять решение о понижении версии. Тем временем некоторые майнеры в ветке 0.7, видя предупреждение в своих клиентах и не зная о рекомендации разработчиков, наоборот бы обновлялись. Ветка 0.8 вырывалась вперед все быстрее и быстрее, и очень скоро окно возможностей было бы упущено. На самом деле, если бы разработчики задержали свое решение хотя бы на несколько часов, вполне возможно, что с 0.7 до 0.8 обновилось бы столько майнеров, что ни один майнер или оператор пула не смог бы в одиночку отменить это решение, и тогда можно только догадываться, сработало ли бы решение о понижении версии вообще.
Вернемся к нашей истории: мы приближаемся к критическому моменту.
Согласен с тем, что цепочка 0.7 является предпочтительной на данный момент.
— 23:44, Джефф Гарзик
BTC Guild: если вы сможете вернуть нас в цепочку 0.7, то я согласен тоже.
— 23:45, Гэвин Андресен
Консенсус достигнут!
Время действовать #
Сразу же разработчики начинают раздавать советы по понижению версии:
surge_: Перейдите на версию 0.7, если запущен майнинг, или просто подождите.
— 23:49, Люк Дашер
doublec: Вы управляете пулом?
— 23:50, Питер Вюлле
Да.
— 23:50, doublec
doublec: Тогда, пожалуйста, перейдите на старую версию.
— 23:50, Питер Вюлле
BTC Guild немедленно начинает действовать…
BTC Guild полностью возвращает настройки блока по умолчанию и переходит на 0.7 в ближайшее время.
— 23:51, BTC Guild
Практически перенес один стратум-узел.
— 00:01, BTC Guild
…не смотря на существенные финансовые потери.
За последние 24 часа я потерял слишком много денег из-за 0.8
— 23:57, BTC Guild
С одной стороны, пул BTC Guild пожертвовал доходами ради блага сети. Но эти действия могут быть обоснованы и с точки зрения максимизации прибыли. Если оператор BTC Guild верил, что ветка 0.7 победит в любом случае (возможно, разработчикам удастся убедить другого оператора крупного пула), то действовать первым будет гораздо выгоднее, поскольку промедление приведет к тому, что BTC Guild еще больше увязнет в обреченной ветке. В любом случае, ключевым фактором, позволившим BTC Guild уверенно понизить версию, является то, что таким образом они могут гарантировать победу ветки 0.7.
Теперь, когда решение принято, пришло время отправить оповещение всем узлам:
Параметры оповещения настроены на передачу в ближайшие 15 минут, истекают через 4 часа.
— 00:07, Гэвин Андресен
Оповещение, о котором идет речь, является образцом краткости: “СРОЧНО: разделение цепочки, прекратите майнинг на версии 0.8”.
В этот момент люди начинают наводнять канал, и наступает хаос. Однако работа сделана, и остался лишь последний шаг.
В 00:29 Питер Вюлле сделал пост на bitcointalk. На этом антикризисные мероприятия, по сути, завершены. Пост гласил:
Всем привет,
Сейчас происходит чрезвычайная ситуация: блокчейн разделился между узлами версии 0.7+, и более ранними, и узлами версии 0.8. Я объясню причины через минуту, но сейчас вам нужно знать вот что:
- После обсуждения в #bitcoin-dev выяснилось, что попытка вернуть всех в старую цепочку — это наименее рискованное решение.
- Если вы майнер, пожалуйста, не майните на коде 0.8. Остановите майнинг или вернитесь обратно на версию 0.7. BTC Guild переходит на 0.7, поэтому старая цепочка скоро получит большинство хэшрейта.
- Если вы мерчант: пожалуйста, прекратите обработку транзакций, пока разделение цепочки не прекратится.
- Если вы работаете на версии 0.7 или старше, клиент, скорее всего, сообщит вам о необходимости обновления. Не следуйте этому совету — предупреждение должно исчезнуть, как только старая цепочка подхватится.
- Если вы не являетесь мерчантом или майнером, не волнуйтесь.
Важно отметить, что он заявил, что ветка 0.7 победит благодаря тому, что пул BTC Guild перешел на нее. Это сделало решение о понижении версии единственно рациональным для всех остальных, и дальше все было лишь вопросом времени.
Что бы произошло, если бы разработчики ничего не предприняли? #
На протяжении всей статьи я подчеркивал, что вариант с понижением версии был правильным, и что скорость реакции разработчиков была крайне важна. Давайте рассмотрим это утверждение подробнее, подумав о том, что бы произошло, если бы разработчики просто пустили все на самотек. Виталик Бутерин считает, что все было бы просто замечательно:
“Если бы разработчики ничего не предприняли, то Биткоин продолжал бы существовать, причиняя неудобства только тем пользователям bitcoind и BitcoinQt, которые были на версии 0.7 и должны были бы обновиться”.
Очевидно, что я не согласен. Мы не можем знать наверняка, что бы произошло, но мы можем сделать обоснованные предположения. Во-первых, форк продолжался бы гораздо дольше — по сути, до тех пор, пока все майнеры, работающие с версией 0.7 или ниже, не отключились бы или не обновили свое программное обеспечение. Учитывая, что многие майнеры оставляют свои машины без присмотра, а другие имеют индивидуальные настройки, которые нелегко быстро обновить, форк мог длиться несколько дней. Это имело бы несколько последствий. Самое очевидное — психологическое воздействие продолжающегося форка было бы серьезным. В отличие от этого, как произошло на самом деле, события разворачивались в течение одной ночи в США и проблема была устранена на следующее утро, а СМИ восхваляли разработчиков за их эффективные действия. Во время инцидента цена биткоина упала на 25%, но сразу же восстановилась почти до прежнего значения.
Еще одно негативное влияние заключается в том, что биржи или платежные сервисы, которые слишком долго обновляют свои клиенты (или отключают транзакции), могут оказаться жертвами крупных атак двойного расходования. Так и случилось, OKPay пострадала от двойной траты $10 000. Это сделал пользователь, пытавшийся доказать свою правоту и публично раскрывший детали; ему повезло в том, что его платеж в OKPay был подтвержден веткой 0.8, но не 0.7. Более длительный форк, скорее всего, усугубил бы проблему и позволил злоумышленникам найти систематический способ создания транзакций двойной траты 2.
Хуже того, возможно, хотя и маловероятно, что ветка 0.7 могла продолжаться бесконечно. Очевидно, что если бы это произошло, это было бы разрушительно для Биткоина, что привело бы к форку самой валюты. Одна из причин, по которой форк может продолжаться, заключается в том, что злоумышленники, производящие “Goldfinger-атаку”, заинтересованы в дестабилизации Биткоина: у них может не быть ресурсов для проведения атаки 51%, но форк может дать им именно такую возможность — они могут просто вложить ресурсы в поддержание жизни форка 0.7 вместо того, чтобы начать атаку с нуля.
Есть еще одна причина, по которой форк мог бы никогда не закончиться. Майнеры, отложившие решение о переходе с 0.7 на 0.8, скажем, на неделю, столкнулись бы с неприятной перспективой лишиться недельного дохода от майнинга. Вместо этого они могли бы сыграть в азартную игру и продолжить работать на ветке 0.7, чтобы в итоге оказаться большой рыбой в маленьком пруду. Если бы ветка 0.7 имела, скажем, 10% от мощности майнинга ветки 0.8, доход майнера умножился бы в десять раз, если бы он добывал в ветке 0.7. Конечно, валюта, которую они заработают, будет “Bitcoin v0.7”, которая будет форком другой валюты — “Bitcoin v0.8”, и будет стоить гораздо меньше, поскольку последняя будет считаться законным Биткоином. Мы анализируем подобную ситуацию в главе 7 “Сообщество, политика и регулирование” нашего учебника по Биткоину или в соответствующих разделах видеолекции.
Хотя точный ход событий, к которым привело бы бездействие, можно оспаривать, очевидно, что решение о понижении версии — гораздо менее рискованное, а скорость и продуманность действий разработчиков достойны похвалы.
Все это резко контрастирует с дисфункциональным состоянием процесса консенсуса по вопросу размера блока. Почему консенсус по этому вопросу не удался? Основная причина заключается в том, что, в отличие от форка, в вопросе размера блока не существует правильного решения; вместо этого есть различные стороны с разными целями, которые не согласуются друг с другом. Кроме того, в случае с форком у разработчиков был хорошо отточенный процесс достижения консенсуса по техническим вопросам, включая ошибки. Например, всем было очевидно, что обсуждение форка должно происходить на IRC-канале #bitcoin-dev; об этом даже не нужно было говорить. С другой стороны, не существует четкого процесса обсуждения вопроса о размере блока, и дискуссия сильно раздроблена между различными каналами. Наконец, когда разработчики пришли к консенсусу по поводу форка, сообщество приняло это решение, потому что доверяло технической компетентности разработчиков. С другой стороны, не существует единой организации, которой сообщество Биткоина доверяло бы принятие решений, имеющих экономические последствия.
Заключение #
Подводя итог, можно сказать, что нам есть чему поучиться, оглядываясь на форк. Биткоин был очень близок к расколу, и очередная ошибка вполне могла бы привести к другому результату. Вопреки мнению Сатоши о том, что протокол консенсуса высечен в камне, он находится под активным управлением человека, и качество этого управления имеет большое значение для его безопасности 3. Централизованное принятие решений спасло ситуацию, и по большей части оно не противоречит децентрализованной природе самой сети. Человеческий фактор становится решающим, когда код дает сбой или требует адаптации с течением времени (например, при обсуждении размера блока). Мы должны признать и принять необходимость сильного руководства и структуры управления, а не рассматривать децентрализацию как волшебную пилюлю.
Спасибо Эндрю Миллеру за комментарии к черновому варианту.
Поддержите переводчика #
Поддержать переводчика можно, отправив немного сат в сети Лайтнинг:
lnurl1dp68gurn8ghj7ampd3kx2ar0veekzar0wd5xjtnrdakj7tnhv4kxctttdehhwm30d3h82unvwqhk7mnv093kcmm4v3unxwg6jxyqf
Поддержка оповещений была удалена из Bitcoin Core в марте 2016 года. Подробнее здесь. — Прим. переводчика. ↩︎
Это связано с тонким техническим моментом: неочевидно, как сделать так, чтобы транзакция попала в одну ветку, но не попала в другую. По умолчанию любая транзакция, которая транслируется, просто попадает в обе ветви, но есть несколько способов попытаться обойти это. Но получив доступ даже к одной транзакции, которая была успешно потрачена дважды, злоумышленник может усилить эффект, постепенно создавая произвольное количество несоответствий между двумя ветвями. ↩︎
Чтобы подчеркнуть, как далек протокол от того, чтобы быть навсегда зафиксированным в спецификации, единственной корректной документацией по протоколу является исходный код эталонной реализации. Даже создание и поддержка совместимой реализации оказалась практически невыполнимой задачей. ↩︎