1315 августа 2010
День, когда появились 184 миллиарда биткоинов
Одна транзакция обошла проверку сумм и создала количество биткоинов, многократно превышавшее предусмотренное. Исправление вышло за несколько часов, но случай показал: надёжность денежных правил зависит от кода, который их выполняет.
В воскресенье 15 августа 2010 года Jeff Garzik обратил внимание на только что добытый блок 74 638 и сумму, которой не должно было существовать. Одна транзакция создала два выхода стоимостью более 92 миллиардов BTC каждый. Их сумма почти в девять тысяч раз превышала запланированное предложение Bitcoin. В 18:08:49 UTC Garzik открыл на форуме тему «Strange block 74638» и опубликовал данные блока. За несколько минут стало ясно: дело не в ошибке обозревателя блоков и не в неверно поставленной десятичной запятой. Сеть приняла блок, нарушавший её собственное денежное правило. Чтобы пользователи и дальше могли верить, что монеты нельзя создавать произвольно, нужно было найти ошибку, исправить программу и убедить достаточно участников продолжить другую ветвь истории.
Странный блок 74 638
Его сообщение было коротким и конкретным. В нём были хеш транзакции и два огромных выхода. Опубликованный позже в том же обсуждении вывод printblock указывал их точную стоимость: каждый содержал 92 233 720 368,54275808 BTC. В блоке также была отдельная транзакция coinbase, выплачивавшая майнеру 50,51 BTC. Рядом с обычным базовым вознаграждением в пятьдесят биткоинов эти два выхода выглядели абсурдно: кто-то только что создал более 184 миллиардов единиц.
Имя автора транзакции и его публичное объяснение неизвестны. Сохранившаяся цепочка показывает, что произошло, но не рассказывает, кто воспользовался ошибкой и зачем. Приписать атаку конкретному хакеру означало бы добавить утверждение, которого нет в источниках. Ясно лишь, что транзакцию составили так, чтобы использовать слабое место проверки.
Сеть приняла ее, потому что старый код проверял отдельные выходы и затем их сумму. Каждый из гигантских выходов умещался в использованном числовом типе, но при сложении вместе они превосходили его верхний предел. Число перелилось в область отрицательных чисел, и последующая проверка ошибочно заключила, что не создается недопустимое положительное значение.
Итак, это не было связано с подделкой подписи, изменением более старой транзакции или захватом большинства хэшрейта. Злоумышленник воспользовался тем, как конкретная реализация обрабатывала целые числа. Математическое правило «не выдавать больше, чем поступает» было правильным; программа не выполнила его так, как люди задумали, из-за переполнения.
Блок уже вошёл в цепочку, за которой следовала сеть. Каждый узел с ошибочной версией считал его действительным, и другие майнеры могли строить поверх него. Поэтому просто сообщить о проблеме было недостаточно. Сообществу нужно было действовать, пока ошибочная история не распространилась дальше, а огромные выходы не начали тратить.
Ошибка между правилом и машиной
Предел в 21 миллион часто называют неизменным законом Bitcoin. Инцидент показал точнее, что это значит. За пределом стоят правила консенсуса, которые каждая программа и каждый полный узел должны выполнять без ошибок. Если все распространённые версии узлов используют одну и ту же ошибочную реализацию, они могут временно принять состояние, противоречащее исходному замыслу.
Переполнение целого числа - это старая проблема программистов. Компьютерный регистр не имеет бесконечного диапазона; после превышения предельного значения дальнейшие арифметические операции могут завершиться совсем на другой стороне числовой оси. В бухгалтерской системе такая мелочь имеет решающее значение. Сумма должна проверяться не только после расчета, но и во время его, и каждая сумма должна оставаться в допустимом диапазоне.
Современный Bitcoin Core выполняет несколько отдельных проверок. Выход не должен быть отрицательным, не должен превышать максимальную денежную массу и текущая сумма после каждого прибавления снова проверяется. Эти строки не появились как абстрактная осторожность. Они несут память о событии, при котором одна отсутствующая защита позволила сети записать экономически невозможную транзакцию.
Ошибка одновременно показывает разницу между спецификацией и общественным ожиданием. Никто на форуме серьёзно не утверждал, что огромные монеты являются легитимными только потому, что их принял старый программный продукт. Участники соглашались, что это является нарушением задуманного правила. Однако это согласие требовало технического средства: новой версии, которая отклонит дефектный блок.
Именно здесь пересекаются код и люди. Код определяет детерминированно, какой блок узел принимает. Люди решают, какой код устанавливают, когда обнаруживают несоответствие с предполагаемыми правилами. Инцидент не был голосованием о новом выпуске; он был гонкой за восстановление правила, которое общество уже считало основой системы.
Переполнение коварно именно тем, что машина не видит абсурда, который человек распознаёт мгновенно. Процессор оперирует числом, хранящимся в ограниченном пространстве; если вычисление превышает его границу, результат может перейти в другую часть диапазона. Старый код проверял отдельные выходные значения, но при сложении не удерживал промежуточную сумму в безопасных пределах. Поэтому транзакция прошла через несколько локально разумных условий и всё же нарушила их общий смысл. Исправление должно было быть конкретным: недостаточно было написать в комментарии, что биткоинов никогда не будет больше, чем 21 миллион. Каждому узлу требовалось правило, способное в каждом вычислении по-настоящему обеспечить соблюдение этого утверждения.
Исправление под давлением
После сообщения на форуме появилась рекомендация временно прекратить приём транзакций и приостановить майнинг. Каждый новый блок поверх ошибочной транзакции увеличивал бы объём работы, которую придётся отбросить. В сети без центрального выключателя Satoshi не мог остановить майнинг. Он мог выпустить исправление и убедить операторов его запустить.
Версия 0.3.10 ввела правильные проверки сумм и отвергала блок 74 638. Исправленные узлы вернулись к последней общей действительной точке, и майнеры начали строить альтернативную ветвь без инфляционной транзакции. Две истории некоторое время конкурировали по объёму накопленной вычислительной работы.
Сатоши впоследствии сообщил, что хорошая цепь опередила плохую. Обновлённое программное обеспечение произвело реорганизацию цепи, и дефектный блок исчез из актуальной истории. Транзакции из ветви, которые сами по себе не были недействительными, могли вернуться в мемпул и впоследствии быть включены повторно; однако гигантские выходы, согласно новым проверкам, существовать не могли.
У исправления была цена. Майнеры на отброшенной ветви потеряли награды, а пользователям пришлось принять, что несколько часов истории не получат продолжения. В 2010 году сеть была небольшой, и координация прошла быстро. В гораздо более крупной экосистеме такое же вмешательство означало бы больше экономических участников, версий программ и споров о точных границах исправления.
Быструю реакцию часто описывают как чудесное вмешательство Satoshi. В действительности она состояла из вполне наблюдаемых шагов: Garzik опубликовал проблему, другие разобрались в переполнении, разработчики подготовили изменение, операторы установили новую версию клиента Bitcoin, а майнеры обеспечили работу правильной ветви. Автор мог предложить исправление, но сеть должна была принять его на практике.
Самое жёсткое правило требует самого смиренного развития
После исправления количество действительных биткоинов вернулось в предусмотренные рамки. Ошибочно созданные миллиарды нельзя было потратить в продолжившей работу цепочке, поэтому постоянной инфляции не возникло. И всё же это не просто курьёз из бета-версии. История напоминает: доверие к денежным правилам опирается на многократно проверенную программу, а не на лозунг.
Биткоин часто противопоставляется системам, в которых центральная власть изменяет предложение по своему решению. Однако и здесь люди не исчезают. Разработчики пишут реализации, рецензенты ищут ошибки, операторы выбирают версии, а майнеры создают порядок блоков. Разница заключается в том, что вмешательство является публичным, и каждый узел может самостоятельно отказаться от правил, с которыми он не согласен.
Это событие также объясняет осторожность, с которой сегодня меняется консенсусный код. Небольшая оптимизация арифметики может иметь денежные последствия. Тесты, дополнительные проверки реализации и медленный обзор не являются бюрократией; они являются защитой от повторения момента, когда несколько битов превратили миллиарды из неприемлемого числа в казалось бы действительное.
Одно сообщение Jeff Garzik не сделало сеть безопасной навсегда, но показало преимущество публичной учётной книги. Каждый мог увидеть странный блок, заново сложить его выходы и проверить исправление. Ошибка не пряталась во внутренней базе данных оператора. Она была перед всем сообществом вместе с доказательством того, что старые узлы её приняли.
Лимит предложения таким образом пережил инцидент иначе, чем это подразумевает слово «неменяющийся». Не потому, что программное обеспечение не могло выйти из строя, а потому, что выход из строя был видимым, существовало общее правило, к которому можно было вернуться, и достаточно участников провели исправление. История 184 миллиардов биткоинов не является опровержением фиксированного предложения. Это история того, что на самом деле требуется для его поддержания.
Это событие также напоминает, что открытость кода сама по себе не устраняет ошибку. Открытый исходный код позволил людям найти, сопоставить и исправить проблему, не дожидаясь единственного поставщика, но решающую роль сыграла внимательность конкретных участников. Кто-то должен был заметить невозможные числа, кто-то — найти дефектное условие, а операторы — принять обновление. Прозрачность создала возможность контроля; лишь действие превратило её в защиту сети. Поэтому эта история остаётся важной и спустя годы: безопасность Bitcoin заключается не в представлении о совершенной исходной программе, а в сочетании точных правил, независимой проверки и способности реагировать на ошибку, не скрывая её.
Люди и понятия в Атласе
Источники и границы истории
- 01BitcoinTalk — Strange block 74638
Первоначальное предупреждение Jeff Garzik, точные значения выходов, разбор переполнения и хронология реакции.
- 02BitcoinTalk — overflow bug SERIOUS
Координация разработчиков во время инцидента, исправление ошибки проверки и переход на исправленную цепочку.
- 03Bitcoin Core — transaction consensus checks
Нынешняя реализация проверок диапазона отдельных выходов и их суммы.