v0.2.7-pre.001
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
<!-- file: docs/validation/000-README.md -->
|
||||
<!-- version: 17 -->
|
||||
<!-- version: 18 -->
|
||||
|
||||
# Validations KSP
|
||||
|
||||
@@ -18,3 +18,4 @@ Documents :
|
||||
- [`007-V0_2_4_HTTP_FINAL_COMPLIANCE.md`](007-V0_2_4_HTTP_FINAL_COMPLIANCE.md) — matrice finale validée de `0.2.4`, inventaire exact 52 current + 14 Deprecated, preuve typed 52/52, audit SIMD final, `KSP-TRANSPORT-007`, workspace complet et deux smokes Devnet passés avant publication stable.
|
||||
- [`008-V0_2_5_WALLET_SECURITY_COMPLIANCE.md`](008-V0_2_5_WALLET_SECURITY_COMPLIANCE.md) — matrice finale validée de la release stable `0.2.5`, threat model V1, canaris adversariaux, reproduction externe des vecteurs, audit de frontières, normalisation Rust/audit structurel, graphes Cargo et checkpoint final `pre.010-fix.003` vert.
|
||||
- [`009-V0_2_6_WALLET_DESK_COMPLIANCE.md`](009-V0_2_6_WALLET_DESK_COMPLIANCE.md) — matrice finale validée de la release stable `0.2.6`, couvrant Wallet Desk, les wires V1/V2, la migration explicite, le runtime Tauri packagé, les frontières sécurité/ownership et le gate opérateur `pre.018-fix.001` avec build final Linux vert.
|
||||
- [`010-V0_2_7_ONCHAIN_WEBSOCKET.md`](010-V0_2_7_ONCHAIN_WEBSOCKET.md) — matrice active de `0.2.7`, ouverte par `pre.001` avec l'inventaire normatif 9 subscribe + 9 unsubscribe, les statuts unstable, le lifecycle, les risques et les preuves à fermer.
|
||||
|
||||
260
docs/validation/010-V0_2_7_ONCHAIN_WEBSOCKET.md
Normal file
260
docs/validation/010-V0_2_7_ONCHAIN_WEBSOCKET.md
Normal file
@@ -0,0 +1,260 @@
|
||||
<!-- file: docs/validation/010-V0_2_7_ONCHAIN_WEBSOCKET.md -->
|
||||
<!-- version: 2 -->
|
||||
|
||||
# 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 :
|
||||
|
||||
```text
|
||||
https://solana.com/docs/rpc/websocket
|
||||
```
|
||||
|
||||
Compte exact de l'index courant :
|
||||
|
||||
```text
|
||||
9 subscribe
|
||||
9 unsubscribe
|
||||
18 méthodes WebSocket totales
|
||||
```
|
||||
|
||||
Répartition statut KSP :
|
||||
|
||||
```text
|
||||
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 :
|
||||
|
||||
```text
|
||||
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 :
|
||||
|
||||
```text
|
||||
--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 :
|
||||
|
||||
```text
|
||||
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 :
|
||||
|
||||
```text
|
||||
--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 | `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 :
|
||||
|
||||
```text
|
||||
tokio-tungstenite 0.30.0
|
||||
futures-util 0.3.34
|
||||
```
|
||||
|
||||
Features prévues :
|
||||
|
||||
```text
|
||||
tokio-tungstenite: default-features=false + connect + rustls-tls-webpki-roots
|
||||
futures-util: default-features=false + std + sink
|
||||
```
|
||||
|
||||
Sources :
|
||||
|
||||
```text
|
||||
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 :
|
||||
|
||||
```text
|
||||
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 :
|
||||
|
||||
```text
|
||||
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 :
|
||||
|
||||
```text
|
||||
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 :
|
||||
|
||||
```text
|
||||
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é
|
||||
```
|
||||
Reference in New Issue
Block a user