Files
khadhroony-solana-project/docs/validation/010-V0_2_7_ONCHAIN_WEBSOCKET.md
2026-08-22 16:39:13 +02:00

28 KiB

Validation 0.2.7 — WebSocket Solana standard

Statut : matrice active, 0.2.7-pre.002. Le gate normatif pre.001 est clos ; les settings, identités, états lifecycle et snapshots sûrs sont maintenant matérialisés. Les preuves runtime socket/subscription restent ouvertes.

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é RpcAccountInfoConfig expose min_context_slot, mais le handler PubSub v4.2.1 le destructure en _ // ignored. KSP ne le compte donc pas comme option WebSocket effective ;
  • programSubscribe : RpcProgramAccountsConfig.with_context est 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 accepte all, allWithVotes ou mentions et rejette un filtre mentions contenant autre chose qu'exactement une adresse ;
  • signatureSubscribe : le handler utilise la signature, commitment et enable_received_notification, sans option WebSocket supplémentaire ;
  • blockSubscribe : le handler consomme le jeu d'options documenté et impose un commitment au moins confirmed ;
  • *Unsubscribe : un ID serveur inconnu produit InvalidParams dans le handler audité ;
  • voteSubscribe : RpcVote.timestamp est Option<UnixTimestamp>, donc optionnel au niveau wire ;
  • slotsUpdatesSubscribe : SlotUpdate possède toujours les sept variantes courantes FirstShredReceived, Completed, CreatedBank, Frozen, Dead, OptimisticConfirmation et Root.

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 Done pre.002
subscription states Requested/Active/Resubscribing/Cancelling/Closed/Failed Done 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 Done pre.002
URL/credentials absents des erreurs validation URL + future connection errors Partial pre.002
URL/credentials absents des logs safe fields pre.002, capture actor future Partial pre.002
snapshots sans URL/raw payload unit shape + public contract Done pre.002
frame/message finis settings bornés, enforcement socket futur Partial pre.002
JSON borné indirectement par message oversized + malformed fixture Planned
queues notifications bornées capacité settings, channel futur Partial pre.002
pending RPC borné + timeout settings bornés, runtime futur Partial pre.002
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 + source audit Done pre.002

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é.

9.1 Checkpoint settings/lifecycle pre.002

Surface publique matérialisée :

WsEndpointUrl
WsProviderName
WsClusterName
WsProtocolKind::SolanaStandard
WsReconnectSettings
WsResubscribePolicy::{Never, ActiveSubscriptions}
WsSessionSettings
WsEndpointSettings
WsTransportSettings
WsSessionId
WsSubscriptionId
WsSessionState
WsSubscriptionState
WsSubscriptionKind
WsSessionSnapshot
WsSubscriptionSnapshot

Gates déterministes ajoutés :

ws:// et wss:// acceptés
HTTP rejeté par WsEndpointUrl
Debug URL redacted
erreur de scheme sans URL/credential
settings session default bornés
zero runtime bound rejeté
reconnect backoff inversé rejeté
endpoint names uniques
au moins un endpoint enabled
Debug WsTransportSettings sans URL/credential
9 familles standard WsSubscriptionKind
snapshots sans URL ni remote subscription id
public API canary crate-root

Logging : TRACING_TARGET reste défini dans constants.rs; les nouveaux événements utilisent exclusivement ksp_logging_lib::trace!, debug! et warn! avec des fields sûrs. Aucun tracing direct n'est ajouté.

Les defaults de taille/queue sont des policies KSP locales, pas des limites Solana. Leur enforcement réel et leurs tests oversized/slow-consumer restent attendus dans les tranches socket/backpressure.

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é