Solana не зберігає історію байткоду програми на ланцюжку. Кожне оновлення безповоротно замінює попередній код у програмному акаунті. Єдиний спосіб відкотити оновлення — повторно розгорнути збережений попередній байткод через upgrade authority (ключ авторизації оновлень). Це означає, що відкат є не вбудованою функцією блокчейну, а процедурою, яку треба спланувати до розгортання.

Збереження попереднього байткоду

Перш ніж виконувати будь-яке оновлення програми, обовʼязково створіть резервну копію поточного байткоду. Без неї відкат неможливий.

Завантажте поточний байткод програми у файл:

Середовище: Solana CLI, підключений до потрібного кластера (devnet / testnet / mainnet-beta).
Передумова: доступ до RPC-вузла, що підтримує запит програмних акаунтів.
Очікуваний результат: файл .so з байткодом поточної версії програми.

Базова команда:

solana program dump PROGRAM_ID backup_before_upgrade.so

Замініть PROGRAM_ID на актуальний адрес програми. Файл backup_before_upgrade.so зберігайте у системі контролю версій або в зашифрованому сховищі разом із іншими артефактами релізу. Рекомендується привʼязувати дамп до конкретного коміту або тегу у репозиторії, щоб завжди було зрозуміло, яку саме версію ви зберегли.

Типова помилка: збереження байткоду лише локально на машині розробника, яка пізніше стає недоступною. Дамп має бути у спільному інфраструктурному сховищі з контролем доступу.

Обмеження: команда dump завантажує байткод, але не зберігає стан даних (accounts), які створила програма. Відкат коду не відновлює дані — це окреме завдання, розглянута нижче.

Процедура відкату через upgrade authority

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

Передумови:

  • Ключова пара upgrade authority (або доступ до мультисигнатури, якщо авторитет передано).
  • Збережений файл .so з попереднім байткодом.
  • Достатній баланс SOL на акаунті, що сплачує комісію за створення буферного акаунта (залежить від розміру байткоду та поточного рент-мінімуму).

Крок 1. Створіть буферний акаунт із попереднім байткодом.

solana program write-buffer backup_before_upgrade.so

CLI поверне адресу створеного буферного акаунта. Збережіть її.

Крок 2. Застосуйте буфер до програми.

solana program deploy --buffer BUFFER_ADDRESS --program-id PROGRAM_ID --upgrade-authority KEYPAIR_PATH

Якщо upgrade authority контролюється мультисигнатурою (наприклад, Squads), замість прямого розгортання використовуйте відповідний інструмент мультисигу для створення транзакції оновлення з цим буфером.

Очікуваний результат: програмний акаунт тепер містить байткод попередньої версії. Усі подальші виклики інструкцій будуть використовувати стару логіку.

Ризики:

  • Якщо між оновленням і відкатом минув значний час, мінімальний рент міг змінитися. Перевірте, чи буферний акаунт створено коректно.
  • Якщо upgrade authority було передано іншому акаунту або скасовано, відкат неможливий — це незворотна дія.
  • Під час відкату на mainnet-beta існує вікно, коли програма вже оновлена, але кеш валідаторів ще містить старий байткод. Це може спричинити нетипову поведінку протягом кількох слотів.

Перевірка даних після відкату

Відкат байткоду не змінює дані в акаунтах, які створила або модифікувала програма. Це ключове джерело ризиків.

Сумісність структур даних. Якщо оновлення, яке ви відкотили, змінювало макет даних акаунтів (додавало поля, змінювало порядок, змінювало типи), старий байткод може не здатен коректно десеріалізувати поточний стан. Наприклад:

  • Якщо нова версія додала поле в кінець структури, стара версія, ймовірно, проігнорує зайві байти — це найбезпечніший сценарій.
  • Якщо нова версія змінила порядок полів або їхні розміри, стара версія прочитає хибні значення. Це може призвести до логічних помилок або паніки програми під час виконання інструкції.
  • Якщо використовується Anchor і змінився дискримінатор акаунта, стара версія не зможе ідентифікувати акаунт взагалі.

Практичні кроки перевірки:

  1. Читання ключових акаунтів. Викличте інструкції читання (get_account, кастомні get_* інструкції) для найважливіших акаунтів і переконайтеся, що десеріалізація проходить без помилок.
  2. Сухий прогін критичних шляхів. Виконайте симуляцію транзакцій (simulateTransaction через RPC) для основних користувацьких сценаріїв без фактичного відправлення. Перевірте, що лог-вивід не містить помилок десеріалізації або паніків.
  3. Перевірка інваріантів. Для кожного критичного інваріанту (баланси, права власності, стани) підтвердіть, що значення відповідають очікуваним після відкату.
  4. Моніторинг помилок у реальному часі. Після відкату уважно стежте за логами транзакцій, що звертаються до програми. Зростання кількості помилок типу InstructionFallbackNotFound або невідомих помилок десеріалізації сигналізує про несумісність даних.

Межа застосування: якщо оновлення змінило структуру даних таким чином, що старий код фізично не здатен їх прочитати, відкат байткоду без міграції даних неможливий. У такому випадку потрібен проміжний реліз, який розуміє новий формат і може мігрувати дані назад, або ручна міграція через окрему утилітарну програму.

Документування причин відкату

Кожен відкат у production — це інцидент, який потребує фіксації. Без документації команда втрачає контекст, а схожі помилки повторюються.

Що має містити запис про відкат:

  • Ідентифікатори версій: хеш коміту або тег версії, яку розгорнули, і хеш коміту, до якої відкотили.
  • Часова шкала: час розгортання проблемної версії, час виявлення проблеми, час відкату.
  • Фактична причина: що саме пішло не так. Описуйте за спостережуваними симптомами і підтвердженими причинами, а не за припущеннями. Наприклад: «інструкція X повертала помилку Y для акаунтів зі станом Z через зміну логіки валідації в коміті ABC» замість «щось зламалося».
  • Опис впливу: які акаунти, транзакції або користувацькі шляхи постраждали. Чи були втрачені кошти або дані.
  • Стан даних після відкату: чи залишилися акаунти у несумісному стані, чи потрібна додаткова міграція.
  • Запобіжні заходи: які зміни в процесі тестування або розгортання мають запобігти повторенню. Наприклад: додати інтеграційний тест для сценарію, що не був покритий, або змінити чек-лист переддеплойної перевірки.

Запис зберігайте у системі трекінгу інцидентів разом із іншими production-подіями. Це забезпечує звʼязок між відкатом, подальшим фіксом і наступним спробою розгортання.

Наступний логічний крок: після стабілізації програми через відкат, налаштуйте автоматизовані перевірки стану, щоб виявляти регресії раніше. Детальніше про це — у матеріалі про те, як налаштувати health checks для Solana-сервісу.

Джерела