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
Оригінальне повідомлення Джеффа Гарзіка, точні виходи, аналіз переповнення та хронологія реакції.
- 02BitcoinTalk — overflow bug SERIOUS
Координація розробників під час інциденту, виправлення помилки перевірки та перехід на виправлений ланцюжок.
- 03Bitcoin Core — transaction consensus checks
Поточна реалізація перевірок діапазону окремих виходів та їх суми.