Private Channels не пройшов аудит безпеки і не рекомендується для використання у виробництві з реальними коштами без ретельної перевірки безпеки.
Розгортаєте екземпляр? Перейдіть до посібника оператора. Інтегруєтесь з наявним екземпляром? Перейдіть до Quickstart. Ця сторінка є довідником з архітектури для обох аудиторій.
Архітектура
Private Channels складається з чотирьох компонентів: двох on-chain програм Solana (Escrow і Withdraw) та двох off-chain сервісів (Gateway і Auth Service). Разом вони утворюють протокол state channel, де кошти зберігаються в Mainnet, але трансфери розраховуються off-chain.
Програма Escrow
Програма Escrow — це on-chain програма Solana, яка зберігає внесені SPL-токени. Вона є якорем довіри системи: усі кошти в кінцевому підсумку зберігаються в escrow, доки оператор не надасть дійсний доказ виключення Sparse Merkle Tree для їх вивільнення.
- Program ID:
9tgHa1DcnaSSUtmMsst8ovKTe1Gfxzezn27KnH9xXYeU - Цей ID компілюється в бінарний файл програми через
declare_id!(). Off-chain сервіси зчитують той самий ID під час компіляції з згенерованого клієнтського крейту, а не зі змінної середовища. - Керує PDA-акаунтами
Instance,AllowedMintтаOperator - Інструкції:
CreateInstance,AllowMint,BlockMint,AddOperator,RemoveOperator,SetNewAdmin,Deposit,ReleaseFunds,ResetSmtRoot
Програма Withdraw
Програма Withdraw працює в мережі приватного каналу, а не в Solana Mainnet.
Користувачі викликають WithdrawFunds, щоб спалити баланс токенів на стороні каналу. Це спалення
не вивільняє кошти автоматично; воно сигналізує оператору, що
запит на виведення очікує на розгляд. Після цього оператор викликає ReleaseFunds у програмі Escrow
з дійсним SMT-доказом для завершення розрахунку.
- Program ID:
J231K9UEpS4y4KAPwGc4gsMNCjKFRMYcQBcjVW7vBhVi - Цей ID компілюється в бінарний файл програми. Off-chain сервіси зчитують той самий ID під час компіляції з згенерованого клієнтського крейту, а не зі змінної середовища.
Gateway
Gateway — це сумісний із Solana JSON-RPC проксі, який маршрутизує клієнтські запити до
write-вузла мережі каналу (для відправлення транзакцій) та read-вузла (для
запитів). Він налаштовується через змінні середовища: GATEWAY_PORT,
GATEWAY_WRITE_URL, GATEWAY_READ_URL.
Ендпоінти перевірки стану (автентифікація не потрібна):
GET /health— перевірка активності; повертає200 {"status":"ok"}GET /ready— глибока перевірка готовності, тестує write + read вузли; повертає200 {"status":"ready"}або503 {"status":"degraded"}
Маршрутизація та доступ до методів RPC
Gateway маршрутизує sendTransaction до write-вузла, а всі інші методи — до
read-вузла. Запити розміром понад 64 КБ відхиляються з HTTP 413. Коли
автентифікація увімкнена, доступ до методів контролюється через JWT-роль. Дивіться
Автентифікація та ролі для
повної матриці методів.
Auth Service
Auth Service — це необов'язковий компонент, який видає HS256 JWT (термін дії 24 години)
для контролю доступу до gateway. Він вмикається, коли встановлена змінна середовища JWT_SECRET.
Без неї gateway приймає всі з'єднання.
Поля JWT: sub (UUID користувача), role ("user" або "operator"), iss
("private-channel-auth"), aud ("private-channel-gateway"), exp (Unix
таймстемп). iss та aud перевіряються конфігурацією JWT у gateway,
а не десеріалізуються в структуру полів застосунку: лише sub, role та
exp доступні коду рівня застосунку.
Ролі:
user— доступ обмежено власними верифікованими гаманцями; не може викликатиgetBlock,getTransactionабоsimulateTransactionoperator— обходить усі перевірки власності; повний доступ до методів RPC; має бути налаштований у базі даних (самостійне підвищення привілеїв неможливе)
Streamer
Streamer — це WebSocket-сервер, який надсилає оновлення стану каналу підключеним клієнтам у реальному часі, усуваючи необхідність опитування RPC. Він опитує PostgreSQL для отримання змін стану. Він є частиною базового стека Docker Compose, а не стеку devnet, який розгортається в цьому посібнику; дивіться довідник конфігурації.
- Порт:
8902, налаштовується черезSTREAMER_PORT - Підключення:
ws://localhost:8902 - Ендпоінт перевірки стану:
GET /health— повертає503, якщо будь-який внутрішній цикл опитування зупиняється більш ніж на 30 секунд
Схема подій WebSocket ще не задокументована публічно. Зверніться до
core/src/bin/streamer.rs
для отримання деталей реалізації до появи офіційної документації.
Конвеєр транзакцій
Transaction -> [1:Dedup] -> [2:SigVerify] -> [3:Sequencer] -> [4:Executor] -> [5:Settler] -> Database
Транзакції, надіслані до Gateway, проходять через п'ятиетапний конвеєр, перш ніж їхній стан буде зафіксовано:
- Dedup — фільтрує дублікати транзакцій до їх входу в конвеєр
- SigVerify — перевіряє підписи транзакцій відносно відкритого ключа підписанта
- Sequencer — детерміновано впорядковує дійсні транзакції для формування канонічної історії
- Executor — виконує транзакції відносно рівня акаунтів каналу (BOB Cache + AccountsDB), оновлюючи баланси off-chain
- Settler — фіксує накопичені результати транзакцій у PostgreSQL та
оновлює кеш Redis; генерує нові blockhash для наступного циклу блоку.
Розрахунок у Mainnet (виклик
ReleaseFunds) обробляється окремо сервісомoperator-private-channel
Ключові можливості
Конфіденційність
Трансфери між учасниками каналу не записуються в Solana Mainnet. Тільки депозити (вхід у канал) та фінальні виведення (вихід із каналу) відображаються on-chain. Особи контрагентів та суми переказів не видимі стороннім спостерігачам під час роботи каналу.
Продуктивність
Off-chain конвеєр виключає час блоку Solana з критичного шляху. Трансфери підтверджуються, коли sequencer їх обробляє, а не коли підтверджується блок Solana. Це забезпечує фіналізацію за частки секунди та пропускну здатність, що перевищує нативний TPS Solana для трансферів рівня застосунку.
Розрахунок
Кожне виведення захищене on-chain доказом Sparse Merkle Tree. Корінь SMT
зберігається в Instance.withdrawal_transactions_root у програмі Escrow.
Коли викликається ReleaseFunds, програма спочатку перевіряє доказ виключення для
небаченого нонсу відносно поточного on-chain кореня, а потім перевіряє окремий
доказ включення для цього нонсу відносно нового кореня, наданого викликаючим. Лише після
проходження обох перевірок зберігається новий корінь, що унеможливлює подвійне витрачання, навіть
якщо ключ оператора скомпрометовано.
Модель безпеки
Ключ адміністратора — контролює створення екземплярів (CreateInstance) та
надання прав операторам (AddOperator / RemoveOperator). Компрометація ключа адміністратора
дозволяє довільне надання прав операторам. SetNewAdmin передає права адміністратора
безповоротно за одну транзакцію; захищайте ключ адміністратора відповідним чином.
Ключі операторів — можуть викликати ReleaseFunds і ResetSmtRoot. Вони не можуть
вивільняти кошти без дійсного SMT-доказу виключення відносно поточного on-chain
кореня. On-chain перевірка verify_smt_exclusion_proof є останньою лінією
захисту від несанкціонованих виведень: скомпрометований ключ оператора сам по собі
не достатній для спустошення escrow.
Корінь SMT — зберігається on-chain у Instance.withdrawal_transactions_root.
Оновлюється атомарно з кожним викликом ReleaseFunds. Оскільки кожен доказ має
посилатися на небачений нонс, подвійне витрачання того самого балансу каналу є
неможливим, навіть якщо ключ оператора скомпрометовано.
Ротація дерева — Instance.current_tree_index відстежує epoch дерева. Коли
викликається ResetSmtRoot, він збільшує індекс дерева та анулює всі
нонси з попереднього epoch дерева, надаючи чисту основу для нових циклів розрахунку.
Безпека операційних ключів
Off-chain сервіси використовують власний словник підписантів, який не пов'язаний із
on-chain повноваженнями адміністратора/оператора, описаними в Моделі безпеки вище.
ADMIN_PRIVATE_KEY є обов'язковим для кожного сервісу оператора та оплачує
комісії за транзакції; окремий, необов'язковий OPERATOR_PRIVATE_KEY надає
on-chain підпис Оператора для ReleaseFunds і ResetSmtRoot, і використовує
значення ADMIN_PRIVATE_KEY, якщо не встановлений. Ніколи не вносьте ключ адміністратора екземпляра
протокольного рівня (що використовується для CreateInstance / AddOperator / SetNewAdmin)
в жодну зі змінних і не розкривайте його під час виконання; зберігайте цей ключ в холодному
офлайн-сховищі.
ReleaseFunds і ResetSmtRoot вимагають двох on-chain підписів: платника комісії
(з ADMIN_PRIVATE_KEY) та уповноваженого PDA Оператора (з
OPERATOR_PRIVATE_KEY, або ADMIN_PRIVATE_KEY, якщо той не встановлений). Покрокове керівництво
devnet у цьому посібнику поміщає згенерований keypair оператора в
ADMIN_PRIVATE_KEY і залишає OPERATOR_PRIVATE_KEY не встановленим, тому той самий keypair
виконує обидві ролі підписанта. Ставтесь до ключа, що потрапляє в ADMIN_PRIVATE_KEY, з
тими самими заходами контролю, що й до приватного ключа гарячого гаманця:
- Зберігайте його лише у файлі
.envз gitignore, ніколи в.env.devnetабо будь-якому зафіксованому конфігу - Для виробничих розгортань розгляньте використання менеджера секретів (AWS Secrets Manager, HashiCorp Vault) замість змінної середовища у відкритому тексті
- keypair адміністратора екземпляра протокольного рівня (що використовується для виклику
AddOperator/SetNewAdmin) слід зберігати в холодному сховищі; він потрібен лише під час налаштування екземпляра та надання прав операторам, а не під час виконання
SetNewAdmin передає права адміністратора безповоротно в одній транзакції:
поточний адміністратор не має шляху відновлення без співпраці нового адміністратора. Не
викликайте цю функцію без перевірки цільової адреси.
Наступні кроки
Is this page helpful?