Files
khadhroony-solana-project/docs/validation/012-V0_2_9_YELLOWSTONE_GRPC.md
2026-08-25 05:44:41 +02:00

469 lines
22 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!-- file: docs/validation/012-V0_2_9_YELLOWSTONE_GRPC.md -->
<!-- version: 27 -->
# Validation `0.2.9` — Yellowstone gRPC standard + PublicNode
**Statut courant : la validation technique `pre.013-fix.004` est fermée et verte : `clippy --all-targets`, workspace, graphes Cargo, puis smoke PublicNode authentifié Mainnet + Testnet `2/2 PASS`. `pre.014` réconcilie et ferme cette matrice documentaire ; seule la tranche `pre.015` de préparation de publication restera avant `rel.001`.**
## 1. Autorités et baseline courante
Autorités :
```text
RULES.md + docs/rules/*
plan 016 courant
code réel Transport/Config
prompts/014-V0_2_9_START_PROMPT.md pour les contraintes non supersédées
deltas/0.2.9/* pour l'historique immuable et les décisions postérieures au prompt
upstream Yellowstone primaire
```
Baseline opérateur immédiatement avant `pre.012` (`0.2.9-pre.011`) :
| Gate | Résultat |
|------------------------------------------|--------------------------|
| `cargo fmt --all` | PASS |
| audit Rust workspace | PASS, 0 candidate export |
| `cargo check --workspace` | PASS |
| `cargo clippy --workspace --all-targets` | PASS sans warning |
| Config unit | 113/113 PASS |
| Config public API | 15/15 PASS |
| Config ownership | 5/5 PASS |
| Transport unit | 383/383 PASS |
| Transport public API | 49/49 PASS |
| Transport release completeness | 43/43 PASS |
| Transport doctests | 4/4 PASS |
| workspace dependency canary | 3/3 PASS |
| `cargo test --workspace` | PASS |
Cette baseline est le seuil de non-régression de `pre.012`.
## 2. Gate dépendances et licence
| Exigence | Décision / preuve | État |
|--------------------------------|------------------------------------------|----------|
| proto officiel sans vendoring | `yellowstone-grpc-proto ^12.6` | **PASS** |
| pas de client upstream runtime | `yellowstone-grpc-client` absent | **PASS** |
| runtime Tonic KSP-owned | `tonic ^0.14` + `tonic-prost ^0.14` | **PASS** |
| proto subtree compatible | Apache-2.0 selon `LICENSING.md` upstream | **PASS** |
| source AGPL copiée | aucune | **PASS** |
| raw client Tonic public | aucun | **PASS** |
| graph final | graphes `pre.013` inspectés | **PASS** |
Le graphe de dépendances n'est pas modifié par `pre.012`; aucune nouvelle dépendance Cargo n'est introduite dans cette tranche.
## 3. Matrice service `Geyser`
| RPC | Classification | Cible | Preuve | Verdict |
|-----------------------|--------------------------------|-------|---------------------------------|----------|
| `Subscribe` | standard | oui | stream bidi local + lifecycle | **PASS** |
| `SubscribeDeshred` | extension/pré-exécution Triton | non | exclusion documentée | **OUT** |
| `SubscribeReplayInfo` | standard unary | oui | fixture unary + reconnect tests | **PASS** |
| `Ping` | standard unary | oui | fixture exact echo | **PASS** |
| `GetLatestBlockhash` | standard unary | oui | fixture typed | **PASS** |
| `GetBlockHeight` | standard unary | oui | fixture typed | **PASS** |
| `GetSlot` | standard unary | oui | fixture typed | **PASS** |
| `IsBlockhashValid` | standard unary | oui | fixture typed + invalid input | **PASS** |
| `GetVersion` | standard unary | oui | fixture typed | **PASS** |
## 4. `SubscribeRequest` — coverage normative
### 4.1 Top-level
| Champ | Verdict | Preuve minimale |
|-----------------------|----------|----------------------------------|
| `accounts` | **PASS** | maps typed + wire exact |
| `slots` | **PASS** | maps typed + wire exact |
| `transactions` | **PASS** | maps typed + wire exact |
| `transactions_status` | **PASS** | same filter family, separate map |
| `blocks` | **PASS** | maps typed + wire exact |
| `blocks_meta` | **PASS** | named empty marker preserved |
| `entry` | **PASS** | named empty marker preserved |
| `commitment` | **PASS** | optional wire semantics |
| `accounts_data_slice` | **PASS** | order + bounds |
| `ping` | **PASS** | optional id |
| `from_slot` | **PASS** | optional + replay mutation |
### 4.2 Accounts
```text
account[]
owner[]
filters[]
nonempty_txn_signature?
cuckoo_accounts_filter?
memcmp bytes/base58/base64
datasize
token_account_state
lamports eq/ne/lt/gt
```
Verdict : **PASS** — wire complet retenu, bounds déterministes, payload Debug redacted, malformed fixed-width rejeté.
### 4.3 Slots
```text
filter_by_commitment?
interslot_updates?
processed
confirmed
finalized
first_shred_received
completed
created_bank
dead + dead_error?
```
Verdict : **PASS**.
### 4.4 Transactions et transaction_status
```text
vote?
failed?
signature?
account_include[]
account_exclude[]
account_required[]
cuckoo_account_include?
token_accounts? = ALL | BALANCE_CHANGED
```
Verdict : **PASS** — request wire, transaction storage/meta, status error et malformed signature couverts.
### 4.5 Blocks, block_meta, entry
```text
account_include[]
include_transactions?
include_accounts?
include_entries?
cuckoo_account_include?
blocks_meta marker
entry marker
```
Verdict : **PASS** — block complet, metadata, entries et champs optional/legacy couverts.
## 5. `SubscribeUpdate` — coverage normative
| Variante | Verdict |
|--------------------------------------|----------|
| account | **PASS** |
| slot | **PASS** |
| transaction | **PASS** |
| transaction_status | **PASS** |
| block | **PASS** |
| ping | **PASS** |
| pong | **PASS** |
| block_meta | **PASS** |
| entry | **PASS** |
| top-level `filters[]` / `created_at` | **PASS** |
Les raw protobufs ne sortent pas de la façade publique. Les décodeurs rejettent les formes structurellement invalides sans copier des payloads arbitraires dans les erreurs.
## 6. Settings, bounds et redaction
| Contrôle | État |
|-----------------------------------------------|--------------------|
| URL `http/https` seulement et longueur bornée | **PASS** |
| URL Debug redacted | **PASS** |
| metadata key/value/count bornés | **PASS** |
| metadata secret/public distincte | **PASS** Transport |
| timeouts non nuls et bornés | **PASS** |
| reconnect bounds cohérents | **PASS** |
| inbound/outbound message sizes | **PASS** |
| request/update queue capacities | **PASS** |
| filter group/name bounds | **PASS** |
| account/owner/memcmp/data slice bounds | **PASS** |
| transaction/block selectors bounds | **PASS** |
| remote `Status` message/details non recopiés | **PASS** |
| Transport -> env/config | absent ou **PASS** |
## 7. Lifecycle, backpressure et replay
| Exigence | Verdict | Preuve |
|------------------------------|-----------------|------------------------------------------------|
| stream bidi unique | **PASS** | round-trip fixture |
| mutation request | **PASS** | same request channel |
| server Ping / client reply | **PASS** | actor test |
| Pong decode | **PASS** | update decode |
| server half-close | **PASS** | state terminal observable |
| explicit client close | **PASS** | half-close avant deadline |
| hostile server shutdown | **PASS** | close timeout borné |
| slow receiver | **PASS** | overflow terminal observable |
| oversized inbound | **PASS** | Tonic decoder bound |
| oversized outbound | **PASS** | reject avant queue dispatch |
| reconnect backoff | **PASS** | budget borné |
| shutdown pendant backoff | **PASS** | interruption sans nouvelle connexion |
| resubscribe déterministe | **PASS** | last accepted full request |
| reprise `from_slot` | **PASS** | dernier slot observé + demande explicite |
| ReplayInfo `first_available` | **PASS** | clamp/gap seulement si prouvé |
| duplicate observability | **PASS** | compteur borné, pas de suppression silencieuse |
| exactly-once/lossless | **NON GARANTI** | contrat explicite |
Snapshot public requis et présent :
```text
reconnect_count
replay_attempt_count
continuity_gap_count
duplicate_update_count
last_requested_from_slot
last_observed_slot
state/error code safe
```
## 8. Gate Config V3 — `pre.011`
### 8.1 Schema et backward compatibility
Le gate opérateur `pre.011` ferme les exigences suivantes :
| Exigence | Preuve | Verdict |
|------------------------------------------|-----------------------------------------|----------|
| schema `$id` V3 | `urn:ksp:schema:std.transport:v3` | **PASS** |
| branches V1/V2 conservées | fixtures V1, V2 et document committé | **PASS** |
| V1 HTTP-only | `v1_transport_fixture...` | **PASS** |
| V2 HTTP+WS | fixture V2 + compatibilité constructeur | **PASS** |
| V3 HTTP+WS+gRPC | 113 tests Config | **PASS** |
| `grpc_endpoints` optionnel par profil V3 | profil `devnet_public` sans gRPC | **PASS** |
| propriétés inconnues refusées | branches schema strictes | **PASS** |
### 8.2 Mapping runtime
V3 doit mapper :
```text
grpc_defaults -> YellowstoneGrpcSessionSettings
grpc_endpoints[].url -> YellowstoneGrpcEndpointUrl
provider -> YellowstoneGrpcProviderName
cluster -> YellowstoneGrpcClusterName
protocol = solana_yellowstone -> gate Config explicite
metadata -> YellowstoneGrpcMetadataEntry::public
secret_metadata -> YellowstoneGrpcMetadataEntry::secret
session overrides -> merge avec grpc_defaults
```
API :
| Surface | Exigence | Statut source |
|---------------------------------|-------------------------------------|---------------|
| `http_settings()` | inchangée | **OK** |
| `ws_settings()` | V1 None, V2/V3 selon profil | **OK** |
| `grpc_settings()` | V1/V2 None, V3 optionnel | **PASS** |
| `into_transport_settings()` | tuple historique HTTP + WS inchangé | **PASS** |
| `into_all_transport_settings()` | nouveau tuple HTTP + WS + gRPC | **PASS** |
### 8.3 Provenance et secrets
Règles validées :
```text
metadata publique + provenance KSP_SECRET_* -> reject
secret_metadata sans provenance secret -> reject
secret_metadata + variable KSP_PUBLIC_/KSP_* -> reject
secret_metadata + KSP_SECRET_/KSPB_SECRET_ -> accept
segments littéraux autour du secret -> accept
safe_value -> secret segment ********
Transport Debug -> URL/metadata secret absents
```
Les tests V3 démontrent le cas valide et les deux croisements invalides sans exposer les canaris.
### 8.4 PublicNode Mainnet
Profil committé et validé :
```text
profile_id = publicnode_mainnet
provider = publicnode
cluster = mainnet-beta
protocol = solana_yellowstone
url = https://solana-yellowstone-grpc.publicnode.com:443
secret_metadata = x-token <- ${KSP_SECRET_PUBLICNODE_MAINNET_GRPC_X_TOKEN}
```
Le mapping produit un endpoint TLS Yellowstone standard et une metadata secrète redacted. Le smoke final ouvre `Subscribe`, reçoit un update `Slot` non nul et ferme de manière bornée : **PASS**.
### 8.5 PublicNode Testnet
Profil committé et validé :
```text
profile_id = publicnode_testnet
provider = publicnode
cluster = testnet
protocol = solana_yellowstone
url = https://solana-testnet-yellowstone-grpc.publicnode.com:443
secret_metadata = x-token <- ${KSP_SECRET_PUBLICNODE_TESTNET_GRPC_X_TOKEN}
```
Le hostname exact a été fourni par l'opérateur puis validé par le smoke live. `Subscribe` reçoit un update `Slot` non nul : **PASS**.
Le même personal token opérateur a été validé sur les deux réseaux. Les deux variables KSP restent distinctes afin de permettre des valeurs différentes si la policy provider change ; cette modélisation ne constitue pas une preuve que les tokens PublicNode sont network-scoped.
## 9. Provider-neutrality
| Point | Verdict |
|-----------------------------------------------|------------------|
| type public `PublicNodeGrpc*` sans divergence | absent, **PASS** |
| protocol standard encodé comme provider | non, **PASS** |
| provider descriptif séparé | oui, **PASS** |
| auth PublicNode hardcodée dans Transport | non, **PASS** |
| Helius/OrbitFlare runtime gRPC dans `0.2.9` | non, **PASS** |
| provider extensions dans N2 | aucune, **PASS** |
## 10. Non-régressions obligatoires
Le gate final doit préserver :
```text
HTTP current typed 52/52
HTTP historical 14/14 Deprecated/Removed
KSP-TRANSPORT-007 vert
Standard WebSocket 9 familles / 18 opérations
Helius LaserStream WebSocket 7 familles standard + transaction + slotsUpdates, heartbeat provider-owned
Transport -> Config interdit
Transport -> std::env KSP_* interdit
tracing direct Transport interdit
```
La baseline `pre.011` reste conservée. Les changements `pre.013` ont porté uniquement le gate live, la Config PublicNode/Testnet et le harness de smoke ; le gate final `pre.013-fix.004` confirme les non-régressions workspace.
## 11. Historique des gates fermé
Les détails de commandes, warnings corrigés et fichiers exacts restent dans leurs deltas immuables.
| Tranche | Gate consolidé |
|-----------------------------------|---------------------------------------|
| `pre.001` + `fix.001` + `fix.002` | audit/sizing/providers/licence fermé |
| `pre.002` + `fix.001` + `fix.002` | moteur/settings/channel fermé |
| `pre.003` + `fix.001` | TLS/metadata/unary fermé |
| `pre.004` + `fix.001` | Subscribe common fermé |
| `pre.005` + `fix.001` | Accounts/Slots fermé |
| `pre.006` | namespace HTTP fermé |
| `pre.007` | Transactions fermé |
| `pre.008` + `fix.001` | Blocks fermé |
| `pre.009` + `fix.001` | bidi/backpressure fermé |
| `pre.010` + `fix.001` | reconnect/replay fermé sans warning |
| `pre.011` | Config V3/PublicNode mapping fermé |
| `pre.012` + `fix.001` | réaudit + règles de fermeture |
| `pre.013` + `fix.001``fix.004` | live PublicNode + graphes fermé |
| `pre.014` | réconciliation documentaire candidate |
Cette table remplace les anciens appendices numérotés successivement `19.x`, `20`, `21`, etc. qui rendaient le document ambigu.
## 12. Verdict opérateur consolidé jusqu'à `pre.013-fix.004`
Le gate technique final reçu le 2026-08-24 est :
| Exigence | Résultat opérateur |
|-----------------------------------------------|--------------------------------------|
| `cargo fmt --all` | **PASS** |
| audit Rust workspace | **PASS, 0 candidate export** |
| audit Markdown | **PASS, 87 tableaux / 258 fichiers** |
| `cargo check --workspace` | **PASS** |
| `cargo clippy --workspace --all-targets` | **PASS sans warning** |
| Transport unit | **383/383 PASS** |
| Transport public API | **49/49 PASS** |
| Transport release completeness | **43/43 PASS** |
| Transport doctests | **4/4 PASS** |
| Config unit dans workspace | **113/113 PASS** |
| Config ownership dans workspace | **5/5 PASS** |
| Config public API dans workspace | **15/15 PASS** |
| workspace dependencies | **3/3 PASS** |
| `cargo test --workspace` | **PASS** |
| graphes Cargo finaux | **PASS / inspectés** |
| smoke PublicNode Mainnet `Subscribe` + `Slot` | **PASS** |
| smoke PublicNode Testnet `Subscribe` + `Slot` | **PASS** |
| smoke live total | **2/2 PASS** |
Les graphes résolus confirment la stack attendue :
```text
yellowstone-grpc-proto 12.6.0
tonic 0.14.6
tonic-prost 0.14.6
prost 0.14.4
prost-types 0.14.4
yellowstone-grpc-client absent du runtime KSP
```
Les graphes ont été exécutés avant `pre.013-fix.004`; ils restent valides car `fix.004` n'a modifié ni dépendance ni feature Cargo.
## 13. Verdict PublicNode live final
Les essais intermédiaires ont établi deux faits utiles : les appels sans credential peuvent atteindre le service mais recevoir `PERMISSION_DENIED`, et la validation représentative de la foundation doit porter sur `Subscribe` plutôt que sur une unary provider éventuellement restreinte.
Le smoke final :
```text
reçoit deux personal tokens par stdin, Mainnet puis Testnet
accepte que les deux lignes contiennent la même valeur
construit une metadata secrète x-token
ouvre TLS puis Subscribe
filtre slots
attend un YellowstoneSubscribeUpdate::Slot sous timeout
exige slot > 0
ferme de manière bornée
n'expose aucun secret dans URL/Debug/arguments
```
Résultat opérateur final : **Mainnet PASS, Testnet PASS, 2/2**.
Le timeout KSP de half-close est un résultat accepté par le harness uniquement après réception prouvée d'un slot ; le runtime conserve son contrat de timeout explicite.
## 14. Gate `pre.014` — réconciliation documentaire
Cette tranche ne modifie ni runtime, ni Config, ni schema, ni smoke. Elle synchronise le plan, la présente validation, README/USAGE Transport et les références durables avec les faits exécutés en `pre.013`.
Le verdict technique de `0.2.9` est donc **PASS**. Après le gate documentaire `pre.014`, seuls le prompt suivant, `CHANGELOG.md` et `ROADMAP.md` restent à finaliser en `pre.015`.
## 15. Gate `pre.015` — préparation de publication
Payload fonctionnel autorisé :
```text
prompts/015-V0_2_10_START_PROMPT.md
CHANGELOG.md
ROADMAP.md
```
Seuls les fichiers mécaniques de version et de traçabilité (`Cargo.toml`, delta `pre.015`) peuvent s'ajouter à ce payload. Aucun README, USAGE, plan, validation, règle, code, test, schema ou config ne doit être corrigé dans `pre.015`.
Si un tel défaut est découvert, une nouvelle prerelease dédiée est ouverte puis la préparation de publication est rejouée sous un nouveau numéro.
## 16. Verdict stable attendu avant `rel.001`
`0.2.9` peut passer à `rel.001` seulement après la séquence suivante :
```text
pre.013 technique/live fermé
pre.014 réconciliation documentaire fermée
pre.015 prompt/CHANGELOG/ROADMAP fermé
```
Et si tous les invariants suivants sont vrais :
```text
standard vs extension explicitement classifié
SubscribeDeshred OUT documenté
7 unary verts
Subscribe + 9 updates verts
resource/backpressure/lifecycle verts
reconnect/replay sans promesse lossless
Config V3 backward V1/V2
provider/protocol distincts
PublicNode Mainnet live Subscribe + Slot PASS
PublicNode Testnet live Subscribe + Slot PASS
x-token secret requis par les profils PublicNode, aucun secret versionné
HTTP/WS/Helius non régressés
dependency firewall vert
cargo graphs inspectés
README/USAGE réconciliés avant la dernière pre
validation 012 fermée avant la dernière pre
prompt/CHANGELOG/ROADMAP seuls dans la dernière pre
workspace final vert
```