Multisig-рахунок для Solana-програми — це механізм, який розподіляє право виконання критичних операцій (зокрема оновлення програми) між кількома незалежними підписантами. На відміну від єдиного ключа upgrade authority, multisig усуває одну точку відмови й робить процес розгортання прозорим для аудиторів та спільноти. Нижче розглянуто дві основні реалізації, порядок їхнього підключення до CI/CD, приховані ризики централізації та сценарії відновлення при втраті ключів.
Архітектура multisig: Squads, Anchor Multisig
На Solana існують дві принципово різні архітектури multisig, які застосовуються до управління програмами: Squads (поточна версія — V4) та Anchor Multisig. Вони відрізняються моделлю зберігання стану, способом підписання та обмеженнями на розмір транзакції.
Налаштування порогу та учасників
Squads V4 використовує модель vault (сховища) — PDA, що належить програмі Squads. Кожен vault має власний список учасників, поріг (threshold) та налаштування затримки виконання (time lock). Створення vault відбувається через окрему інструкцію програми, після чого upgrade authority програми переноситься на адресу цього vault PDA.
Ключові параметри при створенні vault:
- threshold — мінімальна кількість підписів для виконання транзакції. Для production-програм рекомендується не менше 3 з 5 або 4 з 7.
- time_lock — затримка у слотах між останнім підписом і можливістю виконання. Дозволяє іншим підписантам відкликати транзакцію, якщо виявлено аномалію.
- members — масив публічних ключів із призначеними ролями (owner, proposed, executor). Роль визначає, хто може створювати, підписувати або виконувати транзакції.
Anchor Multisig реалізує класичну модель m-of-n без окремого vault. Стан multisig-акаунта містить список підписантів та поріг. Програма не підтримує time lock і має жорстке обмеження на розмір серіалізованої транзакції (через ліміт 10 КБ на акаунт Solana). Це ускладнює використання Anchor Multisig для оновлення великих програм або транзакцій із багатьма інструкціями.
Критерій вибору між двома реалізаціями:
- Якщо потрібен time lock, гнучкі ролі та підтримка великих транзакцій — Squads V4.
- Якщо проєкт вже використовує Anchor і потребує мінімальної multisig без додаткових залежностей — Anchor Multisig, але з розумінням обмежень на розмір.
Підписання та виконання транзакцій
У Squads V4 процес складається з трьох етапів:
- Створення пропозиції (proposal) — один із учасників із роллю proposer формує транзакцію та відправляє інструкцію
create_proposal. Транзакція зберігається в PDA proposal-акаунта. - Підписання (approval) — інші учасники викликають
approve_proposal. Кожне підписання фіксується в стані proposal. Коли кількість підписів досягає threshold, пропозиція переходить у статус ready. - Виконання (execution) — після спливу time_lock (якщо налаштовано) учасник із роллю executor викликає
execute_transaction. Програма Squads підписує внутрішню транзакцію від імені vault PDA і відправляє її.
У Anchor Multisig процес аналогічний, але без етапу time lock: create_transaction → approve (m разів) → execute_transaction. Відсутність затримки означає, що після досягнення порогу транзакція може бути виконана миттєво будь-ким із підписантів.
Типова помилка: спроба підписати proposal тим самим ключем, яким було створено, без окремого виклику approve. У Squads створення не є автоматичним підписанням — це дві окремі інструкції.
Інтеграція multisig у процес розгортання
Перенос upgrade authority на multisig змінює CI/CD-пайплайн: замість прямого виклику solana program deploy або anchor deploy з одиночним ключем, процес розділяється на підготовку транзакції оновлення та її проходження через multisig.
Передумови:
- Upgrade authority програми вже перенесено на vault PDA (Squads) або multisig-акаунт (Anchor Multisig).
- Учасники multisig мають локальні ключі або доступ через Hardware Security Module (HSM) / ключовий менеджер.
- Зібраний файл
.soпрограми перевірено на testnet або devnet із тим самим байткодом, що планується до розгортання на mainnet-beta.
Кроки інтеграції:
- Формування буфера оновлення. Створіть buffer-акаунт із новим байткодом:
Збережіть адресу buffer-акаунта, що повернеться у CLI.solana program write-buffer --url https://api.mainnet-beta.solana.com ./target/deploy/your_program.so - Створення пропозиції оновлення. Замість прямого виклику upgrade, сформуйте інструкцію
program_upgradeз параметрами: buffer-адреса, адреса програми, upgrade authority (vault PDA). У Squads це робиться через SDK або CLI:
Перевірте, що згенерована пропозиція містить саме інструкцію upgrade, а не іншу операцію.squads propose --vault <VAULT_PDA> --program <PROGRAM_ID> --buffer <BUFFER_ADDRESS> - Збір підписів. Кожен підписант незалежно перевіряє хеш buffer-акаунта та виконує approve. У автоматизованому пайплайні це може бути окремий крок у CI, який чекає на ручне підтвердження через захищений канал.
- Виконання після time_lock. Після спливу затримки будь-який executor виконує пропозицію. Перевірте результат:
Порівняйте поле data length із очікуваним значенням.solana program show <PROGRAM_ID>
Очікуваний результат: програма оновлена, upgrade authority залишається за multisig, історія пропозицій зберігається на ланцюжку для аудиту.
План відкату: якщо після оновлення виявлено критичний дефект, процес повторюється з попереднім байткодом. Для цього має бути збережений попередній buffer або можливість швидко перезібрати попередню версію з тегом у VCS. Якщо програма не має backward-incompatible змін у структурі даних, відкат безпечний. Якщо змінено формат акаунтів — відкат може призвести до втрати даних, і це треба оцінити до розгортання.
Обмеження: розмір оновлюваної програми не може перевищувати початковий розмір, виділений під програмний акаунт. Якщо новий байткод більший, спочатку потрібно виконати program extend — це окрема інструкція, яка також має проходити через multisig.
Ризики централізації в multisig
Наявність multisig не гарантує децентралізацію. Фактична централізація виникає, коли:
- Усі ключі належать одній організації. Навіть якщо технічно налаштовано 3-of-5, але всі п'ять ключів зберігаються на серверах однієї компанії, ризик компрометації еквівалентний одиночному ключу. Аудитори перевіряють не лише налаштування threshold, а й фактичний розподіл ключів між незалежними сторонами.
- Поріг занадто низький. Конфігурація 1-of-3 або 2-of-5 дає менший запас міцності, ніж 3-of-5. При 2-of-5 зловмиснику достатньо скомпрометувати два ключі з п'яти.
- Відсутність time_lock. Без затримки між останнім підписом і виконанням інші підписанти не мають часу на реакцію. Це критично для програм, що керують значними коштами.
- Неможливість ротації учасників. Якщо архітектура не дозволяє замінити підписанта без повного пересоздання multisig (як у деяких спрощених реалізаціях), втрата одного ключа може заблокувати оновлення програми назавжди.
- Єдиний executor. Якщо право виконання належить одній особі, вона може затримувати або блокувати виконання вже підписаних пропозицій.
Мінімізація ризиків:
- Розподіляти ключі між щонайменше двома юридично незалежними організаціями (наприклад, розробник + аудитор + фаундейшн).
- Використовувати HSM або air-gapped пристрої для зберігання ключів підписантів.
- Налаштовувати time_lock не менше ніж на кілька годин для production-програм.
- Регулярно проводити ротацію ключів через механізм, наданий multisig-програмою.
- Фіксувати розподіл ключів у публічному документі, який аудитується разом із кодом.
Відновлення доступу при втраті ключів
Втрата ключа підписанта — це не втрата upgrade authority (якщо поріг ще досяжний), але ситуація, що вимагає негайної реакції. Стратегія залежить від того, скільки ключів втрачено відносно порогу.
Сценарій 1: втрачено менше ключів, ніж (n − threshold).
Якщо налаштовано 3-of-5 і втрачено один ключ, поріг все ще досяжний. Дії:
- Зібрати підписи решти учасників для створення пропозиції про ротацію: видалення втраченого ключа та додавання нового.
- У Squads V4 це робиться через інструкцію
set_member(для зміни ролі або видалення) таadd_member. Обидві інструкції проходять через стандартний процес propose → approve → execute. - Після виконання новий учасник отримує відповідну роль, і multisig повертається до повної працездатності.
Сценарій 2: втрачено рівно (n − threshold) ключів.
Наприклад, 3-of-5 і втрачено два ключі. Поріг технічно досяжний (три ключі залишилися), але подальша втрата хоча б одного ключа зробить multisig недієздатним. Дії аналогічні до сценарію 1, але мають виконуватися терміново, поки поріг ще досяжний.
Сценарій 3: втрачено threshold або більше ключів.
Наприклад, 3-of-5 і втрачено три ключі. Multisig стає недієздатним: жодна пропозиція не може набрати необхідну кількість підписів. У цьому випадку:
- Оновлення програми неможливе через цей multisig. Програма залишається працювати з поточним байткодом, але не може бути оновлена або закрита.
- Механізму відновлення на рівні ланцюжка не існує — це фундаментальна властивість моделі без дозволу. Ніхто, включно з розробниками Squads або Solana Labs, не може обійти поріг підписів.
- Єдиний шлях — якщо програма передбачає міграційний механізм (наприклад, можливість перевести управління на новий контракт через іншу інструкцію, що не вимагає upgrade authority), можна скористатися ним. Якщо такого механізму немає — програма фіксується в поточному стані назавжди.
Профілактика втрати ключів:
- Генерувати ключі підписантів у захищених середовищах (HSM, air-gapped машини) і створювати щонайменше дві незалежні резервні копії кожного ключа у фізично розділених локаціях.
- Використовувати Shamir's Secret Sharing (SSS) для розподілу окремих ключів між кількома довіреними особами, щоб жодна з них не мала повного ключа.
- Регулярно перевіряти доступність ключів (наприклад, раз на квартал — підписувати тестову пропозицію кожним ключем).
- Мати запасних підписантів (napkin signers) — осіб із ключами, які не входять до поточного складу, але можуть бути додані через ротацію у разі втрати основних.
Важливе застереження: не плутати відновлення multisig із відновленням upgrade authority. Якщо upgrade authority належить multisig-акаунту, а не окремому ключу, то компрометація або втрата одиночного ключа підписанта не дає зловмиснику права оновити програму самостійно. Але вона зменшує запас міцності й вимагає негайної ротації.