Огляд

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 або simulateTransaction
  • operator — обходить усі перевірки власності; повний доступ до методів 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, проходять через п'ятиетапний конвеєр, перш ніж їхній стан буде зафіксовано:

  1. Dedup — фільтрує дублікати транзакцій до їх входу в конвеєр
  2. SigVerify — перевіряє підписи транзакцій відносно відкритого ключа підписанта
  3. Sequencer — детерміновано впорядковує дійсні транзакції для формування канонічної історії
  4. Executor — виконує транзакції відносно рівня акаунтів каналу (BOB Cache + AccountsDB), оновлюючи баланси off-chain
  5. 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?