Files
khadhroony-solana-project/docs/validation/010-V0_2_7_ONCHAIN_WEBSOCKET.md
2026-08-22 15:34:03 +02:00

20 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 avant 0.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. Source Agave ciblée pour ambiguïtés

Les pages officielles WebSocket du 2026-08-22 lient actuellement Agave v3.1.8 pour les handlers PubSub :

https://github.com/anza-xyz/agave/blob/v3.1.8/rpc/src/rpc_pubsub.rs
https://github.com/anza-xyz/agave/blob/v3.1.8/rpc/src/rpc_subscriptions.rs

Constats ciblés :

  • accountSubscribe : le type partagé RpcAccountInfoConfig expose min_context_slot, mais le handler PubSub v3.1.8 le destructure en _ // ignored. KSP ne le compte donc pas comme option WebSocket effective ;
  • programSubscribe : RpcProgramAccountsConfig.with_context est lu dans ProgramSubscriptionParams, le trait exposé dans rpc_pubsub.rs utilise Subscriber<RpcResponse<RpcKeyedAccount>>, le helper check_commitment_and_notify construit un RpcResponse avec contexte, et aucune consommation with_context n'a été retrouvée dans rpc_subscriptions.rs lors de l'audit ;
  • 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<i64>, ce qui justifie de préserver l'optionalité wire sans valeur inventée.

Décisions compliance : transmettre programSubscribe.withContext malgré l'écart observé et accepter les formes contextée/non-contextée ; ne pas promettre accountSubscribe.minContextSlot tant qu'il est ignoré upstream ; conserver vote.timestamp comme champ optionnel/tolérant.

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 ActiveSubscriptions`, ordre local déterministe
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
Config -> WsTransportSettings
Transport -X-> Config

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
inventaire exact 18 = 9+9                              OK
audit dependencies candidates                          OK
state machines / reconnect / resubscribe                DECIDED
backpressure / cancellation / shutdown / secrets        DECIDED
shape Config V2 minimal                                 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é