26 KiB
Validation 0.2.7 — WebSocket Solana standard
Statut : matrice initiale ouverte par
0.2.7-pre.001. Les colonnes de preuve seront consolidées au fil des prereleases puis fermées avant0.2.7-rel.001.
1. Baseline normative
Audit officiel effectué le 22 août 2026 contre :
https://solana.com/docs/rpc/websocket
Compte exact de l'index courant :
9 subscribe
9 unsubscribe
18 méthodes WebSocket totales
Répartition statut KSP :
12 méthodes appartenant à 6 paires documentées non marquées unstable/deprecated
6 méthodes appartenant à 3 paires unstable : block, slotsUpdates, vote
0 méthode de l'index courant marquée Deprecated
Pour une paire unstable, l'unsubscribe associé est classé Unstable pair dans KSP même si sa propre page n'affiche pas nécessairement le bandeau, car il n'existe que pour annuler la subscription unstable correspondante.
2. Matrice exhaustive des 18 opérations
| # | Méthode | Type | Statut pre.001 |
Paramètres / résultat essentiels | Notification / paire | Stratégie de test | Source officielle | Compliance |
|---|---|---|---|---|---|---|---|---|
| 1 | accountSubscribe |
subscribe | Stable/documented | pubkey ; config commitment, encoding, dataSlice ; result numeric id ; minContextSlot upstream actuellement ignoré, donc non promis |
accountNotification |
fixture encodings/config + subscribe/notify | https://solana.com/docs/rpc/websocket/accountsubscribe |
Planned pre.009 |
| 2 | accountUnsubscribe |
unsubscribe | Stable/documented | remote id ; true or RPC error unknown id |
account pair | handle local -> remote id fixture | https://solana.com/docs/rpc/websocket/accountunsubscribe |
Planned pre.009 |
| 3 | blockSubscribe |
subscribe | Unstable | all/mentions filter ; confirmed/finalized ; encoding ; tx details ; max tx version ; showRewards |
blockNotification |
all options + null block/error + validator capability fixture | https://solana.com/docs/rpc/websocket/blocksubscribe |
Planned pre.011 |
| 4 | blockUnsubscribe |
unsubscribe | Unstable pair | remote id ; boolean/error | block pair | generic registry unsubscribe | https://solana.com/docs/rpc/websocket/blockunsubscribe |
Planned pre.011 |
| 5 | logsSubscribe |
subscribe | Stable/documented | all, allWithVotes, exactly one mentions; commitment |
logsNotification |
3 filters + invalid multi-mention + notification | https://solana.com/docs/rpc/websocket/logssubscribe |
Planned pre.009 |
| 6 | logsUnsubscribe |
unsubscribe | Stable/documented | remote id ; boolean/error | logs pair | generic registry unsubscribe | https://solana.com/docs/rpc/websocket/logsunsubscribe |
Planned pre.009 |
| 7 | programSubscribe |
subscribe | Stable/documented | program pubkey ; commitment ; filters ; encoding ; dataSlice ; withContext |
programNotification |
contexted/non-contexted fixtures + filters | https://solana.com/docs/rpc/websocket/programsubscribe |
Planned pre.009 |
| 8 | programUnsubscribe |
unsubscribe | Stable/documented | remote id ; boolean/error | program pair | generic registry unsubscribe | https://solana.com/docs/rpc/websocket/programunsubscribe |
Planned pre.009 |
| 9 | rootSubscribe |
subscribe | Stable/documented | no params ; numeric id | rootNotification => u64 |
exact root fixture | https://solana.com/docs/rpc/websocket/rootsubscribe |
Planned pre.010 |
| 10 | rootUnsubscribe |
unsubscribe | Stable/documented | remote id ; boolean/error | root pair | generic registry unsubscribe | https://solana.com/docs/rpc/websocket/rootunsubscribe |
Planned pre.010 |
| 11 | signatureSubscribe |
subscribe | Stable/documented | first transaction signature ; commitment ; enableReceivedNotification |
signatureNotification early string or terminal error object |
early + terminal + auto-close/no-resubscribe | https://solana.com/docs/rpc/websocket/signaturesubscribe |
Planned pre.010 |
| 12 | signatureUnsubscribe |
unsubscribe | Stable/documented | remote id before terminal fire ; boolean/error | signature pair | cancel before terminal + stale after terminal | https://solana.com/docs/rpc/websocket/signatureunsubscribe |
Planned pre.010 |
| 13 | slotSubscribe |
subscribe | Stable/documented | no params ; numeric id | slotNotification {slot,parent,root} |
exact fixture + live smoke candidate | https://solana.com/docs/rpc/websocket/slotsubscribe |
Planned pre.010 |
| 14 | slotUnsubscribe |
unsubscribe | Stable/documented | remote id ; boolean/error | slot pair | generic registry unsubscribe | https://solana.com/docs/rpc/websocket/slotunsubscribe |
Planned pre.010 |
| 15 | slotsUpdatesSubscribe |
subscribe | Unstable | no params ; numeric id | tagged slotsUpdatesNotification |
each known variant + unknown fallback | https://solana.com/docs/rpc/websocket/slotsupdatessubscribe |
Planned pre.011 |
| 16 | slotsUpdatesUnsubscribe |
unsubscribe | Unstable pair | remote id ; boolean/error | slotsUpdates pair | generic registry unsubscribe | https://solana.com/docs/rpc/websocket/slotsupdatesunsubscribe |
Planned pre.011 |
| 17 | voteSubscribe |
subscribe | Unstable | no params ; validator flag required | voteNotification |
fields + timestamp omitted/null/value + warning | https://solana.com/docs/rpc/websocket/votesubscribe |
Planned pre.011 |
| 18 | voteUnsubscribe |
unsubscribe | Unstable pair | remote id ; boolean/error | vote pair | generic registry unsubscribe | https://solana.com/docs/rpc/websocket/voteunsubscribe |
Planned pre.011 |
3. Notification matrix
| Subscribe | Notification | Shape à préserver | Point lossless / lifecycle |
|---|---|---|---|
accountSubscribe |
accountNotification |
contextual account payload | reuse account DTOs/encodings/dataSlice |
programSubscribe |
programNotification |
keyed account, documenté avec contexte | accepter contexted/non-contexted à cause de l'écart docs/source audité ; préserver withContext |
logsSubscribe |
logsNotification |
context + {signature, err, logs} |
err nullable ; filtre mentions exactement une adresse |
signatureSubscribe |
signatureNotification |
context + "receivedSignature" ou {err} |
terminal object clôt la subscription ; early string ne la clôt pas |
slotSubscribe |
slotNotification |
{slot,parent,root} |
non-contextual |
rootSubscribe |
rootNotification |
u64 |
non-contextual |
blockSubscribe |
blockNotification |
context + {slot, block, err} |
unstable ; block/err nullable ; variants block selon config |
slotsUpdatesSubscribe |
slotsUpdatesNotification |
tagged union slot lifecycle | unstable ; fallback unknown/raw borné |
voteSubscribe |
voteNotification |
{votePubkey,slots,hash,timestamp,signature} |
unstable/pre-consensus ; timestamp tolerant wire |
Les contexts WebSocket documentés omettent apiVersion. SolanaRpcContext.api_version: Option<String> est compatible avec cette omission.
4. Baselines Git Agave et SIMD
4.1 Hiérarchie de contrôle
La compliance applique le même modèle que la compliance HTTP finale :
documentation Solana actuelle
-> surface publique annoncée
Git Agave tag courant audité v4.2.1
-> implémentation réelle et types wire
SIMD main
-> évolutions Activated, Review, Draft ou Idea à surveiller
Les pages Solana peuvent lier une révision Agave plus ancienne. KSP ne confond donc pas le lien source embarqué dans une page documentaire avec la baseline Git courante. Au 2026-08-22, Agave v4.2.1 est disponible sur Git et devient la baseline d'implémentation de 0.2.7.
Sources Agave ciblées :
https://github.com/anza-xyz/agave/blob/v4.2.1/rpc/src/rpc_pubsub.rs
https://github.com/anza-xyz/agave/blob/v4.2.1/rpc/src/rpc_subscriptions.rs
https://github.com/anza-xyz/agave/blob/v4.2.1/rpc-client-types/src/response.rs
4.2 Constats Agave v4.2.1
Le cross-check du tag courant confirme les 9 subscribe + 9 unsubscribe déjà inventoriés par la documentation publique et ne révèle aucune opération PubSub standard supplémentaire.
Constats ciblés :
accountSubscribe: le type partagéRpcAccountInfoConfigexposemin_context_slot, mais le handler PubSubv4.2.1le destructure en_ // ignored. KSP ne le compte donc pas comme option WebSocket effective ;programSubscribe:RpcProgramAccountsConfig.with_contextest lu et doit rester dans le contrat KSP ; la tolérance contexted/non-contexted reste requise pour ne pas convertir les divergences docs/source/provider en perte wire ;logsSubscribe: le handler accepteall,allWithVotesoumentionset rejette un filtrementionscontenant autre chose qu'exactement une adresse ;signatureSubscribe: le handler utilise la signature,commitmentetenable_received_notification, sans option WebSocket supplémentaire ;blockSubscribe: le handler consomme le jeu d'options documenté et impose un commitment au moinsconfirmed;*Unsubscribe: un ID serveur inconnu produitInvalidParamsdans le handler audité ;voteSubscribe:RpcVote.timestampestOption<UnixTimestamp>, donc optionnel au niveau wire ;slotsUpdatesSubscribe:SlotUpdatepossède toujours les sept variantes courantesFirstShredReceived,Completed,CreatedBank,Frozen,Dead,OptimisticConfirmationetRoot.
Décisions compliance : transmettre programSubscribe.withContext, accepter les formes contextée/non-contextée, ne pas promettre accountSubscribe.minContextSlot tant qu'il est ignoré upstream, conserver vote.timestamp optionnel et garder un fallback borné pour toute future variante SlotUpdate inconnue.
4.3 Audit SIMD ciblé
Aucun SIMD audité n'ajoute actuellement une dixième famille de subscription standard à la surface Agave v4.2.1. Ils modifient en revanche des hypothèses que KSP doit éviter de figer.
| SIMD | Statut au 2026-08-22 | Conséquence WebSocket KSP |
|---|---|---|
0118 Partitioned Epoch Rewards Distribution |
Activated | conserver les DTOs bloc/rewards HTTP déjà lossless, dont numRewardPartitions omitted, null ou valeur |
0291 Commission Rate in Basis Points |
Review | conserver les représentations de commission upstream indépendantes lorsqu'elles sont présentes |
0296 Larger Transaction Size |
Review | proposition jusqu'à 4096 octets : ne pas déduire les limites WS de l'ancienne taille transaction 1232 ; surveiller blockSubscribe |
0298 Bank Hash in Block Footer |
Idea | aucun bankHash spéculatif dans le wire courant ; surveiller le DTO bloc partagé |
0301 parent bank hash |
PR fermé, non mergé | aucun parentBankHash spéculatif ; même conclusion que la compliance HTTP |
0307 Add Block Footer |
Review | aucun footer spéculatif ; réauditer blockSubscribe lorsque l'upstream l'expose réellement |
0326 Alpenglow |
Review | ne pas figer les sémantiques TowerBFT de voteSubscribe ou optimisticConfirmation dans un contrat durable |
0337 Alpenglow Fast Leader Handover Markers |
Review | nouveaux block markers futurs : surveiller shape et taille, sans ajout WS anticipé |
0384 Alpenglow migration |
Review | des notifications RPC commitment/optimistic confirmation peuvent être suspendues pendant migration ; aucune hypothèse de séquence exhaustive |
0385 Transaction V1 |
Review | maxSupportedTransactionVersion et les versions transaction restent génériques ; ne pas caper KSP à v0 |
Sources SIMD :
https://github.com/solana-foundation/solana-improvement-documents/blob/main/proposals/0118-partitioned-epoch-reward-distribution.md
https://github.com/solana-foundation/solana-improvement-documents/blob/main/proposals/0291-commission-rate-in-basis-points.md
https://github.com/solana-foundation/solana-improvement-documents/blob/main/proposals/0296-larger-transactions.md
https://github.com/solana-foundation/solana-improvement-documents/blob/main/proposals/0298-bank-hash-in-block-footer.md
https://github.com/solana-foundation/solana-improvement-documents/pull/301
https://github.com/solana-foundation/solana-improvement-documents/blob/main/proposals/0307-add-block-footer.md
https://github.com/solana-foundation/solana-improvement-documents/blob/main/proposals/0326-alpenglow.md
https://github.com/solana-foundation/solana-improvement-documents/blob/main/proposals/0337-parent-ready-update-marker.md
https://github.com/solana-foundation/solana-improvement-documents/blob/main/proposals/0384-alpenglow-migration.md
https://github.com/solana-foundation/solana-improvement-documents/blob/main/proposals/0385-transaction-v1.md
Les limites WebSocket sont donc des bornes KSP configurables et finies, jamais une transposition en dur de l'ancienne limite transaction de 1232 octets.
5. Méthodes unstable
blockSubscribe
Conditions officielles :
--rpc-pubsub-enable-block-subscription
--enable-rpc-transaction-history
KSP : warning centralisé à la création, test fixture toujours disponible, smoke live non requis.
slotsUpdatesSubscribe
Le format est explicitement annoncé comme susceptible de changer. Variants actuels :
firstShredReceived slot,timestamp
completed slot,timestamp
createdBank slot,parent,timestamp
frozen slot,timestamp,stats
dead slot,timestamp,err
optimisticConfirmation slot,timestamp
root slot,timestamp
stats actuel : numTransactionEntries, numSuccessfulTransactions, numFailedTransactions, maxTransactionsPerEntry.
voteSubscribe
Condition officielle :
--rpc-pubsub-enable-vote-subscription
Les votes observés sont gossip/pre-consensus ; aucune garantie d'entrée dans le ledger. Transport les livre comme wire, sans interprétation métier.
6. Lifecycle compliance initiale
| Contrat | Décision pre.001 |
Gate cible |
|---|---|---|
| plusieurs sessions / même URL | création physique explicite ; aucun singleton/pool automatique | pre.004, pre.012 |
| plusieurs subs / session | registry actor par session | pre.006 |
| ID public subscription | local KSP stable | pre.006 |
| ID serveur | éphémère interne et remappé | pre.006/pre.007 |
| session states | Disconnected/Connecting/Active/Reconnecting/Closing/Closed/Failed | pre.002 |
| subscription states | Requested/Active/Resubscribing/Cancelling/Closed/Failed | pre.002 |
| reconnect | physique uniquement, budget/backoff finis | pre.007 |
| resubscribe | policy Never ou ActiveSubscriptions, ordre local déterministe |
pre.007 |
| continuity | gap observable, aucune promesse lossless | pre.007 |
| backpressure | queue par sub bounded ; overflow => fail local explicite | pre.008 |
| shutdown | explicite, bounded, annule reconnect et subscriptions | pre.005 |
| keepalive | pas de ping applicatif périodique sans besoin démontré | pre.005 |
7. Threat/security compliance initiale
| Invariant | Preuve attendue | Statut |
|---|---|---|
URL/credentials absents de Debug |
unit tests URL wrapper | Planned |
| URL/credentials absents des erreurs | adversarial connection errors | Planned |
| URL/credentials absents des logs | writer/capture KSP logging | Planned |
| snapshots sans URL/raw payload | public API canary | Planned |
| frame/message finis | oversized server fixture | Planned |
| JSON borné indirectement par message | oversized + malformed fixture | Planned |
| queues notifications bornées | slow consumer fixture | Planned |
| pending RPC borné + timeout | no-response fixture | Planned |
| reconnect loop bornée | repeated disconnect fixture | Planned |
| unsubscribe pendant reconnect ne resubscribe pas | race fixture | Planned |
| signature terminale ne resubscribe pas | terminal fixture | Planned |
| shutdown ne bloque pas | peer hostile/no close ack fixture | Planned |
| no Store/Program/Wallet/Config dep dans Transport | cargo tree + source canary | Planned |
no direct tracing dans Transport |
workspace audit/canary | Planned |
8. Dependency compliance initiale
Candidate retenue au gate :
tokio-tungstenite 0.30.0
futures-util 0.3.34
Features prévues :
tokio-tungstenite: default-features=false + connect + rustls-tls-webpki-roots
futures-util: default-features=false + std + sink
Sources :
https://docs.rs/crate/tokio-tungstenite/0.30.0
https://docs.rs/crate/tokio-tungstenite/0.30.0/features
https://docs.rs/crate/futures-util/0.3.34
Alternatives auditées mais non retenues : tokio-websockets 0.13.3, fastwebsockets 0.10.0.
Aucune de ces dependencies n'est ajoutée par pre.001; le graphe Cargo stable ne change pas dans ce gate hors signal de version workspace.
9. Config compliance initiale
V1 actuel : HTTP-only strict. Décision :
V1 -> support de lecture conservé, WS vide
V2 -> HTTP existant + ws_defaults + profiles[].ws_endpoints
profiles[].ws_endpoints[].kind -> discriminateur de famille/protocole WS
0.2.7 -> seule valeur supportée : solana_standard
Config -> WsTransportSettings
Transport -X-> Config
Le type Transport correspondant au discriminateur est prévu #[non_exhaustive]. L'objectif est de pouvoir ajouter ultérieurement une famille telle que Helius Enhanced WebSocket sans créer un nouveau conteneur Config ni injecter des options provider-specific dans les settings Solana standard. Toute valeur inconnue reste explicitement rejetée en 0.2.7; aucun paramètre Helius n'est implémenté par anticipation.
La schema V1 n'est pas assouplie. Une schema V2 explicite remplace la fixture standard au moment où l'adapter est matérialisé.
10. Validation du gate pre.001
Exécuté dans le sandbox :
archive stable v0.2.6 vérifiée OK
lecture règles/architecture/plans/validation OK
inventaire Transport/Config réel OK
archive bot3 WebSocket auditée OK
audit docs officielles WebSocket OK
cross-check Git Agave v4.2.1 OK
audit SIMD WebSocket ciblé OK
inventaire exact 18 = 9+9 OK
audit dependencies candidates OK
state machines / reconnect / resubscribe DECIDED
backpressure / cancellation / shutdown / secrets DECIDED
shape Config V2 + discriminateur famille WS DECIDED
plan/sizing OK
python3 scripts/audit_rust_workspace_rules.py baseline OK
Tenté mais non exécutable dans le sandbox :
cargo fmt --all cargo absent
cargo check --workspace cargo absent
cargo clippy --workspace --all-targets cargo absent
La matrice ne considère donc pas pre.001 techniquement validé par Cargo tant que l'opérateur n'a pas exécuté ces gates sur son checkout.
11. Critères finaux à transformer en preuves
Avant rel.001, cette matrice doit obtenir :
18/18 méthodes official-index accounted
9/9 subscribe wrappers public typed
9/9 unsubscribe couverts par handles/registry
0 option officielle perdue
0 fuite URL/credential
N sessions same URL prouvé
N subscriptions same session prouvé
reconnect/resubscribe/backpressure/shutdown gates verts
unstable warnings centralisés
HTTP 52+14 non régressé
Config V1 backward + V2 WS validés
smoke live opt-in documenté
cargo tree inspecté
cargo test --workspace vert
README/USAGE synchronisés
prompt 0.2.8 préparé