15 августа 2010 года Биткоин пережил одну из самых опасных атак за всю свою историю. В блоке №74638 неизвестный эксплуатировал критическую уязвимость в коде Bitcoin Core и создал из воздуха… 184 миллиарда BTC — в десятки тысяч раз больше, чем предусмотрено лимитом в 21 миллион монет.
Это событие стало важнейшей вехой в понимании того, как устроен Биткоин и что именно обеспечивает его устойчивость — не столько код, сколько люди, стоящие за ним.
⚠️ Что произошло?
Блок 74638
- Дата: 15 августа 2010 года
- Блок: №74638
- Суть бага: В результате переполнения целочисленной переменной (integer overflow), один из участников сети смог создать две транзакции по 92,2 миллиарда BTC каждая — в сумме 184 миллиарда BTC.
Почему баг сработал?
Bitcoin Core на тот момент не проверял сумму выходов транзакции на переполнение чисел. В C/C++ это означает, что если сумма становится больше максимально допустимого значения (например, 2^64
), она обнуляется или переходит в отрицательное значение, позволяя обойти проверку валидности.
if (txout_total > MAX_MONEY) // эта проверка не сработала из-за переполнения
Таким образом, злоумышленник смог обойти лимит монет, встроенный в протокол.
🚨 Реакция сообщества и исправление
Уязвимость была замечена очень быстро. Уже в течение нескольких часов после обнаружения:
- Сатоши Накамото лично выпустил патч Bitcoin версии 0.3.10, устраняющий уязвимость.
- Была внедрена строгая проверка суммы выходов транзакции.
- Блок 74638 и все последующие на его основе были откатаны.
- Узлы сети обновились на новую версию и начали майнить блоки на «чистой» цепочке.
- Через 5 часов зловредная цепочка была вытеснена из консенсуса.
Это был хардфорк, но не запланированный, а экстренный — и все же он прошёл быстро и эффективно благодаря скоординированным действиям сообщества.
🧠 Что это значит для Биткоина?
📌 Миф: «Биткоин — это доверие к коду»
Многие сегодня повторяют мантру о том, что Биткоин децентрализован, устойчив, и всё решается кодом. Но в августе 2010 года именно код дал сбой — и спасла ситуацию не магия алгоритмов, а люди:
- Кто-то заметил аномалию.
- Кто-то понял, в чем проблема.
- Кто-то написал и опубликовал исправление.
- Кто-то убедил майнеров и участников сети обновиться.
Это событие показало: в основе Биткоина лежит социальный консенсус, а не только машинный.
🔐 Как изменилась архитектура после инцидента?
После инцидента:
- Была внедрена жёсткая проверка на превышение лимита монет.
- Введены более строгие условия валидации транзакций.
- Усилено тестирование новых релизов.
- Сообщество стало больше осознавать важность наблюдения и ответственности.
📚 Делаем Резюме
Баг на 184 миллиарда BTC — это не просто ошибка, это лакмусовая бумажка децентрализованных систем. Он показал, что:
- Код может дать сбой.
- Люди, понимающие, как работает система, — её настоящие хранители.
- Доверие в Биткоине — это не только про математические доказательства, но и про зрелость и ответственность сообщества.
Биткоин выжил не потому, что он безупречен. А потому, что сообщество было готово защитить его.
Если хочешь, могу добавить в статью технические детали кода, ссылки на архив форума Bitcointalk по этой теме или инфографику.
Хвала Злоумышленнику
Злоумышленник мог бы создать и меньшую сумму, но, скорее всего, он намеренно выбрал огромную цифру — 184 миллиарда BTC, чтобы:
✅ 1. Проверить границы и спровоцировать переполнение
- В языке программирования C++, на котором написан Bitcoin Core, переполнение целочисленных значений (
integer overflow
) происходит при превышении максимального значения типа данных. - Тип
int64_t
(signed 64-bit integer), используемый для хранения суммы сатоши (1 BTC = 100,000,000 сатоши), имеет лимит около ±9.22 × 10^18
. - Значения, близкие к этому пределу, как раз и могут вызвать непредсказуемое поведение — вроде обнуления, отрицательных значений или «оборачивания» числа.
→ Злоумышленник, скорее всего, сознательно протестировал крайние значения, чтобы спровоцировать баг.
✅ 2. Убедиться, что атака очевидна
- Если бы он создал, скажем, 1000 BTC, это выглядело бы нормально, и никто не заметил бы сразу.
- 184 миллиарда BTC — это настолько аномально, что привлекло моментальное внимание сообщества.
Это был способ сигнализировать об уязвимости громко, почти как «white-hat» (этический хакер), но без объяснений.
✅ 3. Игра на эффекте: продемонстрировать уязвимость протокола
- Возможно, целью было не обогатиться, а показать миру, что в Биткоине всё еще есть критические дыры.
- В 2010 году Биткоин только набирал обороты, и такие атаки могли разрушить доверие к проекту.
💡 Интересный факт
Никто не потратил эти 184 миллиарда BTC. Они были быстро замечены, а цепочка с багом отклонена. Поэтому никакой реальной финансовой выгоды злоумышленник не получил.
🔎 Вывод
Злоумышленник выбрал огромную сумму не случайно. Это была демонстрация уязвимости через резонансную и очевидную аномалию. Маленькая сумма осталась бы незамеченной, а огромная — мгновенно спровоцировала реакцию.
Хочешь, могу сделать блок с техническим примером кода переполнения или диаграмму, как это выглядело в блоке.
Вот технический пример на C++, который иллюстрирует суть бага с переполнением, аналогичного тому, что произошёл 15 августа 2010 года в Биткоине.
💻 Пример: переполнение int64_t
при вычислении суммы выходов
🔹 Исходные условия:
- Сатоши в коде хранятся как 64-битное целое число
int64_t
. - Лимит: 21 млн BTC =
2.1 * 10^15
сатоши. - Проверка должна быть: сумма выходов ≤ 21 млн BTC (в сатоши).
🔹 Код с потенциальным багом:
#include
#include int main() {
// Каждое значение — 92.2 миллиарда BTC в сатоши
int64_t txout1 = 9223372036854775807; // Максимальное значение int64_t
int64_t txout2 = 100; // Любая малая суммаint64_t total = txout1 + txout2; // тут происходит переполнениеstd::cout << "txout1: " << txout1 << std::endl;
std::cout << "txout2: " << txout2 << std::endl;
std::cout << "total: " << total << std::endl; // даст отрицательное число!// Проверка валидности — не сработает
if (total < 21000000LL * 100000000LL) {
std::cout << "Сумма допустима" << std::endl;
} else {
std::cout << "Сумма превышает лимит!" << std::endl;
}
return 0;
}
📉 Что произойдёт?
txout1
— это максимальное допустимое значение для int64_t
: 9223372036854775807
- При сложении с любым числом произойдёт переполнение → значение станет отрицательным или «обнулится» в пределах диапазона.
- Проверка
if (total < MAX_MONEY)
не сработает, потому что total
— уже отрицательное число, и оно «проходит» под лимитом.
🛠 Как это устранили в Bitcoin Core
После инцидента был добавлен код, который явно проверяет переполнение при каждом добавлении:
if (!MoneyRange(txout.nValue))
return state.DoS(100, false, REJECT_INVALID, "txout.nValue out of range");CAmount nValueOut = 0;
for (const auto& txout : tx.vout) {
nValueOut += txout.nValue;
if (!MoneyRange(nValueOut))
return state.DoS(100, false, REJECT_INVALID, "txout total out of range");
}
Функция MoneyRange()
гарантирует, что значения не выходят за допустимый диапазон.
24