Три случая, когда баг чуть не сломал биткоин
За шестнадцать с лишним лет существования биткоина криптографию сети не взломали ни разу. А вот обычный код, написанный людьми, подводил трижды, и каждый раз по-своему серьёзно: один раз из воздуха создали больше монет, чем должно существовать за всю историю сети, второй раз сеть буквально раскололась надвое, третий раз чуть не научились печатать биткоины бесконечно.
Три эпизода, растянутые на восемь лет - от 2010 до 2018 года, - показывают то, о чём редко говорят в разговорах о безопасности биткоина: устойчивость сети держится не на неуязвимости кода, а на скорости, с которой сообщество реагирует на ошибки. Разбираем каждый случай по порядку.
184 миллиарда монет из воздуха
15 августа 2010 года кто-то, чья личность не установлена до сих пор, воспользовался багом в коде биткоина и создал в блоке №74 638 ровно 184 467 440 737,09551616 BTC - при том, что по протоколу вообще не может существовать больше 21 миллиона монет. Деньги разошлись на два адреса, каждый получил чуть больше 92,2 миллиарда BTC.
Причина - классическая ошибка программирования, переполнение переменной: код, который проверял корректность транзакций, не был рассчитан на настолько большие числа, и при суммировании выходов результат просто «переполнился» и стал невалидным без должной проверки.
Аномалию заметил разработчик Джефф Гарзик - будущий CEO компании Bloq - на форуме Bitcoin Talk. Патч выпустили спустя всего пять часов, реализовал его лично псевдонимный создатель биткоина Сатоши Накамото: в сети сделали обновление (софт-форк), после которого сеть "откатила" историю транзакций (произошла реорганизация цепи) вместе с вознаграждениями за майнинг, накопленными на этих блоках, - 184 миллиарда «лишних» монет исчезли вместе с ними.
Показательно, что произошло дальше: инцидент не подорвал доверие к биткоину, а скорее укрепил его - за оставшиеся месяцы 2010 года курс вырос больше чем на 300%, с 7 до 30 центов. Быстрая и прозрачная реакция создателя сети на серьёзнейший баг в самом начале истории биткоина показала, что систему не так легко сломать, как могло показаться скептикам.
Когда сеть буквально раскололась на два биткоина
12 марта 2013 года, начиная с блока №225430, блокчейн биткоина физически разделился на два: одна половина сети добавляла блоки к одной версии цепочки, другая к другой. Следующие шесть часов в мире одновременно существовали две разные версии истории всех транзакций биткоина.
Причина оказалась почти анекдотичной. Новая версия клиента 0.8 перешла на более быструю базу данных LevelDB вместо BerkeleyDB, и разработчики не заметили, что вместе с этим случайно поменялись и правила самого протокола. У старой базы был лимит в 10 тысяч одновременных блокировок записи, а один из блоков потребовал больше - версия 0.7 его отклонила, версия 0.8 приняла как обычно.
Разработчикам пришлось выбирать, какую цепочку поддержать: сеть не может работать с двумя параллельными версиями истории одновременно. Решили в пользу старой версии 0.7, хотя цепочка на 0.8 уже обгоняла её на 13 блоков. Крупнейшие майнинг-пулы координировались напрямую через IRC-канал разработчиков и синхронно переключились обратно.
Экономический ущерб оказался небольшим: 26 тысяч долларов в виде наград за 24 блока, оставшихся на отброшенной ветке, и одна двойная трата на 10 тысяч долларов. Курс просел на 24%, но быстро отыграл падение.
Уладить всё удалось быстро по одной причине: свыше 70% вычислительной мощности сети тогда контролировалось небольшим числом майнинг-пулов, и разработчикам хватило нескольких часов, чтобы лично связаться с операторами и убедить их переключиться. Мы уже разбирали, почему за 16 лет майнинг практически полностью сместился именно в сторону пулов, а не индивидуальной добычи, в отдельном материале о математике соло-майнинга - и этот же эффект концентрации, обычно считающийся уязвимостью децентрализации, в 2013 году сыграл ключевую роль в быстром спасении сети.
Баг, который позволял печатать биткоины бесконечно
Больше полутора лет в коде Bitcoin Core - главной реализации протокола биткоина - жила уязвимость, которую никто не замечал. Баг попал в код ещё в марте 2017 года вместе с обновлением 0.14.0, задуманным как улучшение производительности сети.
Суть уязвимости заключалась в узлах сети, которые не отклоняли блок с транзакцией, тратящей одни и те же монеты дважды. В версиях 0.14.0–0.14.2 такой блок хотя бы вызывал аварийное отключение узла - неприятно, но безопасно. А вот в версиях 0.15.0–0.16.2 баг стал гораздо серьёзнее: узел мог принять поддельную транзакцию как совершенно нормальную, если монета не была потрачена дважды в одном и том же блоке. Теоретически это позволяло майнеру напечатать монеты из ничего, скопировав собственные, - ровно то, против чего изначально придумывался биткоин.
Уязвимость нашёл разработчик под псевдонимом Awemany и анонимно сообщил о ней команде Bitcoin Core. Патч в виде версии 0.16.3 вышел уже на следующий день.
Экономика гипотетической атаки делала её крайне рискованной для самого атакующего. Майнеру пришлось бы сознательно создать «атакующий» блок и рискнуть потерять честную награду за него (около 13 тысяч долларов) при том, что подделку почти наверняка быстро бы заметили и отвергли, а курс монет с подозрением на бесконечную эмиссию сразу обвалился бы в цене. Уязвимость так и не была использована ни разу за полтора года своего существования.
Что объединяет все три случая
Ни в одном из трёх эпизодов не пострадала сама криптография биткоина - подписи, хеш-функции и математика системы ни разу не были взломаны. Проблема каждый раз крылась в обычном коде: переполнение переменной, несовместимость версий базы данных, ошибка в проверке транзакций - то, что ломается в любом крупном программном продукте.
Общий знаменатель - скорость реакции. В 2010 году патч вышел за пять часов, в 2013-м сеть синхронизировалась обратно за шесть, в 2018-м баг устранили за сутки с момента анонимного репорта. Устойчивость биткоина держится не на идеальности кода, а на том, что сообщество умеет быстро действовать синхронно в критический момент.
Три случая за восемь лет - и за следующие восемь ничего подобного по масштабу больше не повторилось, по крайней мере публично. Неплохое подтверждение того, что система действительно учится на своих ошибках.
Для майнера в этой истории есть и практический вывод: скорость обновления и мониторинг исторически спасали сеть не реже, чем сама её мощность. На пуле K8X статистика по хешрейту и статус сети видны в личном кабинете в реальном времени - так что о любых аномалиях в работе собственной фермы майнер узнаёт сразу.