1511–12 березня 2013 року

Ніч, коли в Біткоїна було дві валідні історії

Новіша та старіша версії Біткоін Кор не погоджувалися щодо одного блоку. Розробники та майнери мали протягом кількох годин вирішити, яку гілку підтримати — і заплатили за це полишеною працею.

Увечері 11 березня 2013 року біткоїнові вузли почали продовжувати дві версії однієї історії. Нова версія Bitcoin 0.8 прийняла блок 225 430 і будувала ланцюг далі на його основі. Частина старіших вузлів із версією 0.7 відхилила блок: для обробки знадобилося більше блокувань бази даних, ніж дозволяв практичний ліміт Berkeley DB. Обидві групи діяли за своїм програмним забезпеченням і вважали власну гілку дійсною. Спочатку новіша гілка мала більшість потужності, зосередженої в майнінгових пулах. Просте очікування радше поглибило б розкол, ніж усунуло його. Розробники, біржі та оператори пулів зібралися в IRC. Без центрального штабу їм треба було знайти шлях, яким достатня частина мережі знову могла б рухатися разом.

01

Один блок, два вердикти

Блок 225 430 не був створений з метою розділити мережу. Він містив однак більше транзакційних входів, ніж попередні блоки, і тим самим завантажив базу даних таким чином, що викрив різницю між версіями. Bitcoin 0.8 використовував LevelDB і обробив блок. Версія 0.7 з Berkeley DB наткнулась на кількість замків і завершилась помилкою.

Причина розколу була небезпечно непомітною. Обидві групи вузлів дотримувалися правил так, як їх могла виконати встановлена програма. Новіша гілка не порушувала задуму правил консенсусу, а старіші вузли не зазнали атаки. Мережу розділило незадокументоване практичне обмеження однієї з технологій баз даних.

Майнери з версією 0.8 будували над новим блоком. Майнери зі старішою версією продовжували від його попередника. Як тільки обидві гілки отримали додаткові блоки, оплата, підтверджена на одній, не мусила існувати на іншій. Користувач не міг безпечно покладатися на звичайну кількість підтверджень, доки не стало ясно, яку історію прийме економічна більшість.

Новіша гілка спочатку несла приблизно шістдесят відсотків хешрейту. За звичайних обставин ланцюг з більшим об'єднаним хешрейтом здобув би перевагу. Однак тут старі вузли не могли прийняти новий блок без огляду на його роботу. Реорганізація сама по собі не перекрила б блок, який місцеве валідуюче програмне забезпечення вважало невалідним.

Інцидент таким чином викрив ліміт простого правила „найбільший ланцюг перемагає“. Точніше перемагає ланцюг з найбільшою працею серед тих, які вузол спочатку визнає валідними. Коли вузли не погоджуються щодо валідності, сам хешрейт не достатній для негайного об'єднання.

02

IRC як провізорна командна кімната

Розробники помітили проблему, коли висоти та хеші відстежуваних вузлів почали відрізнятися. Комунікація зосередилася на IRC-каналі, де було можливо порівнювати логи, продуктивність гілок та реакції великих пулів. Гевін Андресен пізніше в BIP 50 описав хронологію та рішення, які під час ночі були прийняті.

На вибір не було між чисто правильною та явно неправильною гілкою. Підтримка версії 0.8 зберегла б ланцюг з більшим хешрейтом, але відрізала б кількість старіших вузлів. Повернення до гілки 0.7 означало переконати нових майнерів полишити блоки, які вони вже легітимно видобули та за які очікували винагороду.

Практичною причиною для повернення було сумісність. Версія 0.8 могла прийняти менші блоки, створені для старішої гілки, тоді як вузли 0.7 не могли прийняти проблемний блок нової гілки. Якщо хешрейт перейде на гілку, прийнятну для обох груп, мережа може знову об'єднатися без негайного примусового оновлення всіх старіших вузлів.

Це рішення не було наказом, який Андресен міг надіслати через протокол. Розробники зв’язалися з операторами пулів і пояснили ситуацію. Біржам рекомендували призупинити зарахування коштів. Bitcoin.org опублікував попередження й закликав великі пули повернутися до старішої версії програми, щоб мережа знову об’єдналася на сумісній гілці.

Ця координація була швидкою саме тому, що коло ключових учасників було ще відносно малим і люди знали один одного з публічних каналів. Швидкість допомогла мережі врятуватися від тривалого розколу, але водночас показала соціальні зв'язки, на яких залежав ранній рух. Біткоїн не мав голови; однак мав людей, чиї телефонні дзвінки або повідомлення могли перемістити велику частку потужності.

Розмова в IRC не мала юридичної сили й не була прихованим адміністративним ключем. Її значення полягало в тому, що в одному місці вона з'єднала людей із різними можливостями втручання. Розробники могли пояснити причину, пули могли перенаправити хешрейт, біржі — призупинити поповнення, а оператори вузлів — змінити версію. Кожен крок мав власний ризик, і ніхто не міг гарантувати, що інші послухають. Тому рішення підтримати гілку, сумісну з версією 0.7, не було технічним наказом із центру мережі, а скоординованою ставкою на те, що цей шлях найшвидше відновить спільну історію з найменшим впливом на користувачів. Успіх неможливо відокремити від тодішнього малого розміру спільноти, ні подавати як універсальну процедуру кризового реагування.

03

Пули жертвують видобутої працею

Вирішальний крок зробили два оператори: Michael Marsee, відомий як Eleuthria, який керував BTCGuild, та Marek Palatinus зі Slush Pool. Обидва повернулися з версії 0.8 до 0.7 і спрямували обчислювальну потужність на старішу гілку. Це допомогло змінити співвідношення накопиченої роботи між двома історіями.

Не йшлося про безкоштовне жест в таблиці. Блоки, видобуті на полишеній гілці під час реорганізації, перестали бути частиною основного ланцюга, тому їх винагороди не мали залишатися витратними. BIP 50 явно нагадує, що пули жертвували значні гроші, щоб мережа повернулася на спільну гілку.

Як тільки старіша гілка взяла перевагу, оновлені вузли 0.8 могли її прийняти та реорганізувати свою історію. Старіші вузли вже були на ній. Розкол закрився не тому, що одна версія віддалено переписала іншу, а тому, що достатньо велика кількість майнерів створила більше праці над точкою, яку могли перевірити обидві.

Під час інциденту відбулося щонайменше одне велике подвійне витрачання, яке було описано як експеримент, а не запланована атака. Подія все ж показала реальне ризик: транзакція могла бути підтверджена на гілці, яка пізніше буде полишена. Рекомендація зупинити депозити не була панікою; вона захищала служби від бухгалтерських залишків, заснованих на тимчасовій історії.

Пули в цей момент не володіли мережею. Вони могли впливати на порядок блоків хешрейтом, який їм довірили майнери, але не могли змусити кожен повний вузол прийняти довільні правила. Їхній успіх залежав від вузької мети: створити гілку, яку старіші та новіші вузли вважали валідною, та надати їй найбільшу працю.

04

Розбір інциденту замість міфу про перемогу

Гевін Андресен згодом описав інцидент у BIP 50. Документ не стверджує, що мережа працювала бездоганно. Він пояснює причину, перебіг подій, втрату блоків, подвійне витрачання та заходи, покликані раніше виявляти подібні розбіжності. Завдяки оприлюдненому розбору досвід кризової ночі не залишився лише в пам’яті її учасників. Ним могли скористатися й інші розробники.

Одним із уроків було те, що консенсус не включає лише правила, написані в коментарі чи документації. Практичне поведінка широко розгорнутого програмного забезпечення може стати обмеженням мережі, навіть якщо ніхто не мав наміру, щоб воно мало грошовий зміст. Міграція бази даних тому не повинна вважатися чисто внутрішньою зміною, якщо вона може змінити прийняття блоку.

Іншим уроком була необхідність координувати оновлення більш обережно та тестувати блоки біля операційних лімітів. Версія 0.8 принесла покращення продуктивності, але різниця проявила себе лише у фактичному ланцюзі. Після інциденту розробники ввели тимчасові ліміти та підготували шлях, який дозволив старим залежностям пізніше безпечно полишити.

Історія іноді використовується як доказ того, що Біткоїн керується кількома розробниками, іноді як доказ того, що він автоматично незнищенний. Жодна з цих скорочених версій не відповідає дійсності. Люди змогли терміново координувати ремонт, але їм потрібна була співпраця пулів, бірж та операторів вузлів. Програмне забезпечення приймало рішення на кожному комп'ютері окремо, а спільний результат виник лише їхньою взаємодією.

Ніч з 11 на 12 березня закінчилася поверненням до одного основного ланцюга. Але розбіжності не зникли самі собою. Одні учасники помітили проблему, інші призупинили роботу сервісів, а майнери відмовилися від уже виконаної роботи заради сумісної історії. Біткоїн подолав це роздвоєння завдяки поєднанню правил, економічних втрат і готовності людей визнати: цього разу новіша програма має поступитися.

Цінність BIP 50 у тому, що він не завершує розповідь проголошенням перемоги децентралізації. Документ фіксує конкретну причину, хронологію, втрачену роботу та кроки, заплановані для запобігання подібним несподіванкам. Неприємний збій стає основою для подальшого тестування. Водночас залишається питання: скільки неписаних припущень приховано між двома версіями програми, які ми вважаємо сумісними? Консенсус — це більше, ніж перелік правил на папері. Незалежні реалізації та вузли мають отримувати однаковий результат навіть у граничних випадках. Важливість цієї узгодженості стає особливо помітною, коли вона зникає.

Atlas

Люди й поняття в Атласі

FORK13March 2013 Chain SplitGAVINGavin AndresenSLUSHМарек «Slush» ПалатінусPOOLMining PoolNODEFull NodeRULESПравила консенсусуREORGReorg
  1. 01
    BIP 50 — Посмертна звіть про розкол ланцюга березня 2013

    Перша технічна звіть про причину, хешрейт, координацію BTCGuild та Slush Pool, подвійне витрачання та виправлення.

  2. 02
    Bitcoin.org — 11/12 березня 2013 року Інформація про розкол ланцюга

    Добова публічна попередження для торговців та користувачів під час розколу мережі.

  3. 03
    Біткоїн Кор — примітки до випуску версії 0.8.0

    Контекст нової базової шари та змін версії, на якій несподівана не сумісність проявила себе.

Наступна історія · 16Trezor: ключі від Біткоїна в кишеньковому комп'ютері