Private Channels non è stato sottoposto a un audit di sicurezza e non è consigliato per l'uso in produzione con fondi reali senza una revisione approfondita della sicurezza.
Stai effettuando un deployment? Vai alla guida per gli operatori. Stai integrando un'istanza esistente? Vai alla Quickstart. Questa pagina è il riferimento architetturale per entrambi i tipi di utenti.
Architettura
Private Channels è composto da quattro componenti: due programmi Solana on-chain (Escrow e Withdraw) e due servizi off-chain (Gateway e Auth Service). Insieme formano un protocollo di canale di stato in cui i fondi risiedono su Mainnet ma i trasferimenti vengono regolati off-chain.
Programma Escrow
Il Programma Escrow è un programma Solana on-chain che conserva i token SPL depositati. È l'ancora di fiducia del sistema: tutti i fondi risiedono in definitiva in escrow finché un operatore non fornisce una prova di esclusione valida tramite Sparse Merkle Tree per liberarli.
- Program ID:
9tgHa1DcnaSSUtmMsst8ovKTe1Gfxzezn27KnH9xXYeU - Questo ID è compilato nel binario del programma tramite
declare_id!(). I servizi off-chain leggono lo stesso ID in fase di compilazione dal crate client generato, non da una variabile d'ambiente. - Gestisce i PDA
Instance,AllowedMinteOperator - Istruzioni:
CreateInstance,AllowMint,BlockMint,AddOperator,RemoveOperator,SetNewAdmin,Deposit,ReleaseFunds,ResetSmtRoot
Programma Withdraw
Il Programma Withdraw è eseguito sulla rete del canale privato, non su Solana Mainnet.
Gli utenti chiamano WithdrawFunds per bruciare il saldo dei token lato canale. Questa operazione di burn
non rilascia automaticamente i fondi; segnala all'operatore che un
prelievo è in attesa. L'operatore chiama quindi ReleaseFunds sul Programma Escrow
con una prova SMT valida per completare il regolamento.
- Program ID:
J231K9UEpS4y4KAPwGc4gsMNCjKFRMYcQBcjVW7vBhVi - Questo ID è compilato nel binario del programma. I servizi off-chain leggono lo stesso ID in fase di compilazione dal crate client generato, non da una variabile d'ambiente.
Gateway
Il Gateway è un proxy compatibile con Solana JSON-RPC che instrada le richieste dei client al
nodo di scrittura della rete del canale (per l'invio delle transazioni) e al nodo di lettura (per le
query). È configurato tramite variabili d'ambiente: GATEWAY_PORT,
GATEWAY_WRITE_URL, GATEWAY_READ_URL.
Endpoint di health (autenticazione non richiesta):
GET /health- verifica di liveness; restituisce200 {"status":"ok"}GET /ready- readiness approfondita, verifica i nodi di scrittura e lettura; restituisce200 {"status":"ready"}oppure503 {"status":"degraded"}
Routing dei Metodi RPC e Accesso
Il gateway instrada sendTransaction al nodo di scrittura e tutti gli altri metodi al
nodo di lettura. Le richieste superiori a 64 KB vengono rifiutate con HTTP 413. Quando
l'autenticazione è abilitata, l'accesso ai metodi è controllato dal ruolo JWT. Consulta
Autenticazione e Ruoli per la
matrice completa dei metodi.
Auth Service
L'Auth Service è un componente opzionale che emette JWT HS256 (scadenza a 24 ore)
per il controllo degli accessi al gateway. Viene abilitato quando la variabile d'ambiente JWT_SECRET
è impostata. In sua assenza, il gateway accetta tutte le connessioni.
Claim JWT: sub (UUID utente), role ("user" o "operator"), iss
("private-channel-auth"), aud ("private-channel-gateway"), exp (timestamp
Unix). iss e aud sono validati dalla configurazione JWT del gateway,
non deserializzati nella struct dei claim dell'applicazione: solo sub, role e
exp sono disponibili al codice a livello applicativo.
Ruoli:
user- accesso limitato ai propri wallet verificati; non può chiamaregetBlock,getTransactionosimulateTransactionoperator- aggira tutti i controlli di proprietà; accesso completo ai metodi RPC; deve essere provisioning nel database (nessuna escalation self-service)
Streamer
Lo Streamer è un server WebSocket che invia aggiornamenti sullo stato del canale ai client connessi in tempo reale, eliminando la necessità di eseguire polling sull'RPC. Esegue il polling di PostgreSQL per i cambiamenti di stato. Fa parte dello stack Docker Compose base, non dello stack devnet che questa guida distribuisce; consulta il riferimento alla configurazione.
- Porta:
8902, configurabile tramiteSTREAMER_PORT - Connessione:
ws://localhost:8902 - Endpoint di health:
GET /health- restituisce503se un loop di polling interno si blocca per più di 30 secondi
Lo schema degli eventi WebSocket non è ancora documentato pubblicamente. Fare riferimento a
core/src/bin/streamer.rs
per i dettagli implementativi fino a quando non sarà disponibile la documentazione ufficiale.
Pipeline delle Transazioni
Transaction -> [1:Dedup] -> [2:SigVerify] -> [3:Sequencer] -> [4:Executor] -> [5:Settler] -> Database
Le transazioni inviate al Gateway attraversano una pipeline in cinque fasi prima che il loro stato venga consolidato:
- Dedup - filtra le transazioni duplicate prima che entrino nella pipeline
- SigVerify - valida le firme delle transazioni rispetto alla chiave pubblica del firmatario
- Sequencer - ordina deterministicamente le transazioni valide per stabilire una cronologia canonica
- Executor - esegue le transazioni sul layer degli account del canale (BOB Cache + AccountsDB), aggiornando i saldi off-chain
- Settler - consolida i risultati accumulati delle transazioni in PostgreSQL e
aggiorna la cache Redis; genera nuovi blockhash per il prossimo ciclo di blocchi.
Il regolamento su Mainnet (la chiamata a
ReleaseFunds) è gestito separatamente dal serviziooperator-private-channel
Caratteristiche Principali
Privacy
I trasferimenti tra i partecipanti al canale non vengono registrati su Solana Mainnet. Solo i depositi (ingresso nel canale) e i prelievi finali (uscita dal canale) compaiono on-chain. Le identità delle controparti e gli importi dei trasferimenti non sono visibili agli osservatori esterni durante il funzionamento del canale.
Prestazioni
La pipeline off-chain rimuove il block time di Solana dal percorso critico. I trasferimenti vengono confermati quando il sequencer li elabora, non quando un blocco Solana viene confermato. Ciò consente una finalità in tempi inferiori al secondo e un throughput superiore al TPS nativo di Solana per i trasferimenti a livello applicativo.
Regolamento
Ogni prelievo è protetto da una prova Sparse Merkle Tree on-chain. La radice SMT
è memorizzata in Instance.withdrawal_transactions_root nel Programma Escrow.
Quando viene chiamato ReleaseFunds, il programma verifica prima una prova di esclusione per
un nonce mai visto rispetto alla radice on-chain corrente, quindi verifica una prova di
inclusione separata per quel nonce rispetto alla nuova radice fornita dal chiamante. Solo dopo
che entrambi i controlli sono superati viene memorizzata la nuova radice, rendendo impossibile il double-spend anche
se una chiave operatore è compromessa.
Modello di Sicurezza
Chiave admin - controlla la creazione delle istanze (CreateInstance) e il
provisioning degli operatori (AddOperator / RemoveOperator). La compromissione della chiave admin
consente il provisioning arbitrario di operatori. SetNewAdmin trasferisce l'autorità admin
in modo irreversibile in un singolo passaggio; proteggere di conseguenza la chiave admin.
Chiavi operatore - possono chiamare ReleaseFunds e ResetSmtRoot. Non possono
liberare fondi senza una prova di esclusione SMT valida rispetto alla radice on-chain corrente.
Il controllo on-chain verify_smt_exclusion_proof è l'ultima linea di
difesa contro i prelievi non autorizzati: una chiave operatore compromessa da sola non
è sufficiente a svuotare l'escrow.
Radice SMT - memorizzata on-chain in Instance.withdrawal_transactions_root.
Aggiornata atomicamente a ogni chiamata a ReleaseFunds. Poiché ogni prova deve
far riferimento a un nonce mai visto, spendere due volte lo stesso saldo del canale è
impossibile anche se una chiave operatore è compromessa.
Rotazione dell'albero - Instance.current_tree_index tiene traccia degli epoch dell'albero. Quando
viene chiamato ResetSmtRoot, incrementa l'indice dell'albero e invalida tutti i
nonce dell'epoch dell'albero precedente, fornendo una base pulita per i nuovi cicli di regolamento.
Sicurezza Operativa delle Chiavi
I servizi off-chain utilizzano un proprio vocabolario di firmatari, non correlato alle
autorità admin/operatore on-chain descritte nel Modello di Sicurezza sopra.
ADMIN_PRIVATE_KEY è richiesta per ogni servizio operatore e paga le
commissioni di transazione; un OPERATOR_PRIVATE_KEY separato e opzionale fornisce la
firma Operator on-chain per ReleaseFunds e ResetSmtRoot, e utilizza il valore di
ADMIN_PRIVATE_KEY come fallback quando non è impostato. Non inserire mai la chiave admin dell'istanza a livello di protocollo
(usata per CreateInstance / AddOperator / SetNewAdmin)
in nessuna delle due variabili né esporla a runtime; tenere quella chiave cold e offline.
ReleaseFunds e ResetSmtRoot richiedono due firme on-chain: il fee payer
(da ADMIN_PRIVATE_KEY) e l'autorità del PDA Operator (da
OPERATOR_PRIVATE_KEY, oppure ADMIN_PRIVATE_KEY se non impostato). Il walkthrough devnet di questa guida di
deployment inserisce il keypair dell'operatore generato in
ADMIN_PRIVATE_KEY e lascia OPERATOR_PRIVATE_KEY non impostato, così lo stesso keypair
ricopre entrambi i ruoli di firmatario. Applicare alla chiave che finisce in ADMIN_PRIVATE_KEY gli
stessi controlli di una chiave privata di un hot wallet:
- Conservarla solo nel file
.envcon gitignore, mai in.env.devneto in qualsiasi configurazione committata - Per i deployment in produzione, considerare un secrets manager (AWS Secrets Manager, HashiCorp Vault) anziché una variabile d'ambiente in chiaro
- Il keypair admin dell'istanza a livello di protocollo (usato per chiamare
AddOperator/SetNewAdmin) dovrebbe essere tenuto cold; è necessario solo durante la configurazione dell'istanza e il provisioning degli operatori, non durante il runtime
SetNewAdmin trasferisce i diritti admin in modo irreversibile in una singola transazione:
l'admin corrente non ha percorsi di recupero senza la collaborazione del nuovo admin. Non
chiamarlo senza aver verificato l'indirizzo di destinazione.
Prossimi Passi
Is this page helpful?