# Plan `0.2.9` — moteur Yellowstone gRPC + standard Solana + PublicNode > **Statut : `0.2.9-pre.002` — première matérialisation N1 préparée : dépendances Yellowstone/Tonic minimales, settings runtime bornés, error mapping initial et channel Tonic lazy privé. Les gates Cargo restent à exécuter par l’opérateur avant commit. `0.2.9` reste bornée à un moteur client Yellowstone partagé, une façade Solana Yellowstone standard et une première intégration concrète PublicNode. Seuls OrbitFlare puis Helius LaserStream gRPC sont actuellement planifiés comme releases provider suivantes ; les autres providers restent en TODO/IDEAS sans numéro réservé. Chaque prerelease vise 15–20 minutes de travail effectif et la release complète doit rester clôturable dans une seule session de chat.** ## 1. Objet, base et état d'ouverture `0.2.9` introduit dans `ksp-onchain-transport-lib` une première fondation Yellowstone gRPC **standard et provider-neutral**, distincte de HTTP et de WebSocket. Base autoritaire auditée à l'ouverture : ```text archive opérateur = khadhroony-solana-project-v0.2.8-full-from-gitea.zip workspace.package.version initial = 0.2.8 deltas/0.2.8/rel.001.md présent prompts/014-V0_2_9_START_PROMPT.md présent prompt fourni = byte-identique au prompt embarqué metadata .git = absente de l'archive opérateur ``` Le signal d'ouverture est : ```text workspace.package.version = 0.2.9-pre.1 commit attendu = v0.2.9-pre.001 aucun tag prerelease ``` État hérité à ne pas régresser : ```text HTTP Solana 52/52 current typed + 14 historiques Deprecated/Removed KSP-TRANSPORT-007 appliqué WebSocket standard 9 familles / 18 subscribe-unsubscribe Helius LaserStream WS 7 familles standard + transactionSubscribe/unsubscribe Helius heartbeat Ping control frame 60 s, actor-owned Config Transport V1 HTTP + V2 HTTP/WS backward-readable Config -> Transport autorisé Transport -> Config interdit ``` ## 2. Résultat du gate `pre.001` Le gate est **positif avec scope borné**. `0.2.9` peut raisonnablement porter **trois niveaux distincts dans la même crate Transport** : ```text N1 moteur client Yellowstone gRPC partagé channel/TLS/metadata, stream bidi, bounds, backpressure, shutdown, reconnect/replay observables N2 façade protocolaire Solana Yellowstone standard 7 unary retenus + Subscribe standard + filters/updates typed provider-neutral N3 première intégration provider : PublicNode / Allnodes-backed Mainnet + Testnet, capabilities/profile/config + smokes live opt-in sans duplication du moteur ; le wire standard est réutilisé uniquement pour les capacités réellement compatibles ``` Le moteur est **Yellowstone-specific**, pas une abstraction gRPC universelle. Le serveur/plugin Geyser reste hors de KSP ; KSP implémente le client du protocole Yellowstone exposé par les providers. La première intégration PublicNode peut rester volontairement mince si le provider n'ajoute aucun wire ou lifecycle propriétaire : l'objectif est de matérialiser la frontière provider, les capabilities et la validation live, pas de créer artificiellement un second actor/session. Un type/facade provider-specific public n'est justifié que si PublicNode impose une différence réelle de contrat. La compatibilité provider n'est toutefois **jamais présumée totale**. Pour chaque provider, N3 peut : ```text réutiliser N2 pour une capacité Yellowstone réellement compatible restreindre une capacité standard absente/non supportée ajouter une extension provider-specific typed adapter auth/metadata, compression, keepalive, replay/from_slot, limites ou lifecycle ``` Le moteur N1 reste unique. Le wire N2 n'est jamais recopié quand il est identique, mais une divergence réelle de wire ou de sémantique doit être isolée explicitement dans N3 plutôt que masquée derrière le standard. Sont explicitement exclus de `0.2.9` : ```text SubscribeDeshred et pré-exécution/deshred OrbitFlare provider integration Helius LaserStream gRPC provider integration eRPC/Triton/Alchemy/QuickNode/Chainstack/Tatum/Shyft/Solinfra/NodeFlare/autres providers client autoreconnect upstream comme contrat public KSP pool/scheduler automatique complexe de sessions gRPC exactly-once / lossless / ordre global garanti serveur Geyser/plugin validator Store/workers/backfill historique ``` Après `0.2.9`, seules deux releases provider sont actuellement réservées : **OrbitFlare**, puis **Helius LaserStream gRPC**. Elles réutiliseront N1/N2 lorsque compatibles et isoleront leurs restrictions/extensions dans N3. Tous les autres providers restent en TODO/IDEAS sans numéro réservé jusqu'à décision explicite ultérieure. ## 3. Sources internes relues Le gate a relu les règles et documents imposés par le prompt depuis la base stable : ```text RULES.md docs/000-README.md docs/rules/RULES_GENERAL.md docs/rules/RULES_KSP.md docs/rules/RULES_RUST.md docs/rules/RULES_DEPENDENCIES.md docs/rules/RULES_DOCUMENTATION.md docs/rules/FILE_CONTRACTS.md docs/rules/VERSION_WORKFLOW.md docs/rules/PROMPT_STRUCTURE.md docs/architecture/000-README.md docs/architecture/002-LAYERS_AND_DEPENDENCIES.md docs/architecture/003-COMPONENT_CONTRACTS.md docs/architecture/004-COMPONENT_INVENTORY.md docs/architecture/005-DEPENDENCY_GRAPH.md docs/architecture/009-ACQUISITION_WORKERS_AND_JOBS.md docs/architecture/010-APPS_SERVICES_SCENARIOS_AND_CONTROL.md docs/plans/002-FUNCTIONAL_RELEASE_SEQUENCE.md docs/plans/007-V0_2_0_SERIES_PLANNING.md docs/plans/008-V0_2_1_ONCHAIN_HTTP_PLAN.md docs/plans/014-V0_2_7_ONCHAIN_WEBSOCKET_PLAN.md docs/plans/015-V0_2_8_HELIUS_LASERSTREAM_WEBSOCKET_PLAN.md docs/validation/003-V0_2_1_ONCHAIN_HTTP.md docs/validation/005-V0_2_3_KSP_TRANSPORT_007_RETRO_AUDIT.md docs/validation/007-V0_2_4_HTTP_FINAL_COMPLIANCE.md docs/validation/010-V0_2_7_ONCHAIN_WEBSOCKET.md docs/validation/011-V0_2_8_HELIUS_LASERSTREAM_WEBSOCKET.md deltas/0.2.8/rel.001.md ``` Le code réel audité confirme notamment : - Transport possède déjà HTTP et WebSocket dans une seule crate ; - Config dépend de Transport, l'inverse est interdit ; - le schéma Transport V2 est fermé par `additionalProperties: false` et distingue `endpoints` / `ws_endpoints` ; - aucun contrat gRPC n'existe encore ; - les abstractions WebSocket ne doivent pas être réutilisées pour gRPC. ## 4. Baseline stable enregistrée La preuve opérateur fournie juste avant l'ouverture enregistre sur `v0.2.8` : ```text cargo fmt --all OK python3 scripts/audit_rust_workspace_rules.py OK / clean cargo check --workspace OK cargo clippy --workspace --all-targets OK cargo test --workspace OK cargo tree -p ksp-onchain-transport-lib fourni cargo tree --duplicates fourni ``` Sous-ensembles Transport observés pendant `cargo test --workspace` : ```text unit tests 335 passed public_api 41 passed release_completeness 34 passed doc-tests 4 passed live smokes opt-in / ignored par défaut ``` Dépendances directes Transport observées avant gRPC : ```text futures-util 0.3.34 reqwest 0.13.4 serde 1.0.229 serde_json 1.0.151 tokio 1.53.1 tokio-tungstenite 0.30.0 ksp-core-lib 0.2.8 ksp-logging-lib 0.2.8 ``` Le graphe existant contient déjà les familles modernes suivantes via HTTP/WS : ```text bytes 1.x http 1.x hyper 1.x hyper-util 0.1.x tower 0.5.x rustls 0.23.x tokio-rustls 0.26.x ``` Le coût réel de `tonic/prost/yellowstone-grpc-proto` devra néanmoins être mesuré après matérialisation en `pre.002`; aucun doublon n'est préjugé acceptable avant `cargo tree`. ## 5. Audit upstream Yellowstone au 2026-08-23 ### 5.1 Divergence du snapshot du prompt Le snapshot préparatoire du prompt mentionnait `v14.2.2+solana.4.1.0` comme release GitHub observée. Le réaudit courant trouve désormais : ```text release GitHub latest = v15.1.2+solana.4.2.0 publication release = 2026-08-18 Rust annoncé = 1.96.1 ``` Le changelog master indique en outre : ```text 2026-08-17 yellowstone-grpc-geyser 15.1.2 2026-08-10 yellowstone-grpc-proto 12.6.0 2026-07-31 yellowstone-grpc-client 13.3.0 ``` Cela confirme que **version du plugin GitHub, version du client crate et version du proto crate évoluent indépendamment**. Sources primaires : ```text https://github.com/rpcpool/yellowstone-grpc/releases https://github.com/rpcpool/yellowstone-grpc/blob/master/CHANGELOG.md https://github.com/rpcpool/yellowstone-grpc/blob/master/yellowstone-grpc-proto/proto/geyser.proto https://docs.rs/crate/yellowstone-grpc-proto/latest https://docs.rs/crate/yellowstone-grpc-client/latest ``` ### 5.2 Crates publiées retenues pour le gate État publié observé : ```text yellowstone-grpc-client = 13.3.0, publié 2026-07-31 yellowstone-grpc-proto = 12.6.0, publié 2026-08-13 sur docs.rs prost/prost-types = 0.14.x tonic = 0.14.x ``` `yellowstone-grpc-client 13.3.0` dépend notamment de : ```text bytes ^1.10.1 futures ^0.3.24 hyper ^1.4.1 hyper-util ^0.1.7 tokio ^1.47.1 tonic ^0.14.0 tonic-health ^0.14.0 tower ^0.5.0 yellowstone-grpc-proto ^12.5.0 ``` Il expose désormais un `AutoReconnect`, une politique de reconnexion et de la déduplication/replay. Ces capacités sont utiles comme référence, mais ne doivent pas posséder la sémantique publique KSP. `yellowstone-grpc-proto 12.6.0` dépend notamment de : ```text prost ^0.14.0 prost-types ^0.14.0 solana-pubkey ^4.0.0 thiserror ^2.0.16 siphasher ^1 tonic ^0.14.0 optionnel tonic-prost ^0.14.0 optionnel bytes ^1.10.1 optionnel ``` Le `solana-pubkey ^4.0` du proto est compatible en gamme avec le `^4.3` déjà utilisé par KSP ; l'unification exacte sera vérifiée par Cargo en `pre.002`. ### 5.3 Licences Le dépôt upstream déclare : ```text licence par défaut du repository = AGPL-3.0-only ``` mais `LICENSING.md` affecte explicitement **Apache-2.0** aux sous-arbres : ```text examples/ yellowstone-grpc-client/ yellowstone-grpc-client-nodejs/ yellowstone-grpc-proto/ ``` Conséquence du gate : - dépendre de la crate publiée `yellowstone-grpc-proto` est compatible avec la distribution MIT de KSP sous réserve des obligations Apache usuelles ; - aucun fichier provenant des zones AGPL du repository ne sera copié dans KSP ; - KSP ne vendore pas les `.proto` dans la stratégie retenue ; - si un fichier upstream devait être copié ultérieurement, sa provenance et sa licence seraient réauditées fichier par fichier avant incorporation. Sources : ```text https://github.com/rpcpool/yellowstone-grpc/blob/master/LICENSING.md https://docs.rs/crate/yellowstone-grpc-proto/latest ``` ### 5.4 Compatibilité toolchain / build KSP suit la **Rust stable courante de l'opérateur** et ne documente pas de numéro Rust upstream comme objectif de projet. Le seul gate utile est opérationnel : les dépendances finalement retenues doivent compiler avec la stable courante utilisée par le workspace. Résultat de matérialisation `pre.002` : ```text yellowstone-grpc-proto ^12.6 workspace dependency, default-features = false, aucune feature KSP activée tonic ^0.14 workspace dependency, default-features = false ; Transport active seulement `channel` yellowstone-grpc-client absent prost/prost-types aucune dépendance KSP directe tonic-prost aucune dépendance KSP directe à ce stade proto crate publiée/générée ; aucun .proto copié dans KSP protoc aucun outil système KSP ajouté ; la crate proto publiée utilise son build vendored ``` Le feature `tonic` optionnel de `yellowstone-grpc-proto` n'est **pas** activé en `pre.002`. KSP n'a besoin à ce stade que des messages Protobuf générés bruts ; le channel physique est construit directement avec Tonic. Cette décision évite de tirer prématurément la surface client/serveur Tonic générée et laisse `pre.003` choisir explicitement les features supplémentaires réellement nécessaires aux unary/TLS/metadata. Un minimum Rust déclaré par une dépendance n'est enregistré que s'il devient un **blocage réel** lors de la compilation ; il n'est pas suivi comme métrique de release. ## 6. Matrice du service `Geyser` courant Le proto publié `yellowstone-grpc-proto 12.6.0` et le proto master exposent le même inventaire de service observé pendant le gate : | RPC | Forme | Statut | Cible `0.2.9` | Décision | |-----------------------|-------------|----------------------------------------------------------------|---------------|----------------------------------------------| | `Subscribe` | bidi stream | standard Yellowstone | **oui** | fondation principale | | `SubscribeDeshred` | bidi stream | présent dans proto, trajectoire Triton extension/pré-exécution | **non** | report explicite | | `SubscribeReplayInfo` | unary | standard | **oui** | information de replay, pas garantie lossless | | `Ping` | unary | standard | **oui** | canari/liveness unary | | `GetLatestBlockhash` | unary | standard | **oui** | canari typed | | `GetBlockHeight` | unary | standard | **oui** | canari typed | | `GetSlot` | unary | standard | **oui** | canari typed | | `IsBlockhashValid` | unary | standard | **oui** | canari typed | | `GetVersion` | unary | standard | **oui** | canari typed | `SubscribeDeshred` est techniquement publié dans le proto, mais le changelog upstream le rattache explicitement aux **Triton Extension Patches** et décrit la réception de transactions avant exécution. Il reste donc hors fondation provider-neutral `0.2.9`. ## 7. Matrice `SubscribeRequest` Surface standard retenue intégralement : | Champ | Type / sémantique | `0.2.9` | |-----------------------|-------------------------------------------------|--------------------------| | `accounts` | map nom -> `SubscribeRequestFilterAccounts` | oui | | `slots` | map nom -> `SubscribeRequestFilterSlots` | oui | | `transactions` | map nom -> `SubscribeRequestFilterTransactions` | oui | | `transactions_status` | même famille de filtre transaction | oui | | `blocks` | map nom -> `SubscribeRequestFilterBlocks` | oui | | `blocks_meta` | map nom -> filtre vide | oui | | `entry` | map nom -> filtre vide | oui | | `commitment` | optional Processed/Confirmed/Finalized | oui | | `accounts_data_slice` | repeated offset/length | oui | | `ping` | optional request ping/id | oui | | `from_slot` | optional u64 | oui, sémantique prudente | ### 7.1 Accounts ```text account[] owner[] filters[] nonempty_txn_signature? cuckoo_accounts_filter? ``` Filtres account : ```text memcmp { offset, oneof bytes | base58 | base64 } datasize token_account_state lamports { oneof eq | ne | lt | gt } ``` Les formes Cuckoo actuelles sont conservées parce qu'elles appartiennent au proto publié standard observé, pas parce qu'un provider particulier les demande. ### 7.2 Slots ```text filter_by_commitment? interslot_updates? ``` `SlotStatus` courant : ```text processed confirmed finalized first_shred_received completed created_bank dead ``` ### 7.3 Transactions / transaction_status ```text vote? failed? signature? account_include[] account_exclude[] account_required[] cuckoo_account_include? token_accounts? = ALL | BALANCE_CHANGED ``` L'optional `token_accounts` contrôle l'expansion vers les owners de token accounts dans les balances pre/post ; son absence est distincte de ses deux valeurs connues. ### 7.4 Blocks ```text account_include[] include_transactions? include_accounts? include_entries? cuckoo_account_include? ``` ### 7.5 BlocksMeta / Entry Les deux filtres sont actuellement des messages vides : leur **présence nommée** active la famille ; KSP doit donc conserver la distinction absence / map vide / entrée nommée vide au niveau de son contrat logique. ### 7.6 Common ```text commitment? Processed | Confirmed | Finalized accounts_data_slice offset + length ping? id from_slot? u64 ``` KSP appliquera des bornes déterministes avant I/O sur les noms, cardinalités, listes de comptes/owners, memcmp, data slices et tailles de payload. Les valeurs exactes sont un contrat KSP et non une copie aveugle des quotas d'un provider ; elles seront matérialisées avec tests en `pre.004`. ## 8. Matrice `SubscribeUpdate` Le `oneof update_oneof` standard contient exactement neuf variantes observées : | Variante | Champs structurants à préserver | |----------------------|-----------------------------------------------------------------------------| | `account` | account info + slot + `is_startup` | | `slot` | slot + optional parent + status + optional dead_error | | `transaction` | signature/is_vote/transaction/meta/index + slot | | `transaction_status` | slot/signature/is_vote/index/error | | `block` | slot/hash/rewards/time/height/parent/counts + transactions/accounts/entries | | `ping` | marker server ping | | `pong` | id | | `block_meta` | block metadata/counts sans tableaux complets | | `entry` | slot/index/num_hashes/hash/transaction counts/index | Le top-level contient aussi : ```text filters[] noms de filtres correspondants created_at google.protobuf.Timestamp ``` Les types imbriqués `solana-storage.proto` nécessaires aux transactions/blocs seront projetés dans des types KSP sans perte arbitraire de champs utiles. Les types Prost/Yellowstone générés restent internes au backend et ne sont pas réexportés dans l'API publique. ## 9. RPCs unary retenus | RPC | Request | Response | Notes | |-----------------------|---------------------------|------------------------------------------|----------------------------------------| | `SubscribeReplayInfo` | vide | `first_available?` | information de disponibilité seulement | | `Ping` | `count` | `count` | exact echo attendu | | `GetLatestBlockhash` | `commitment?` | slot, blockhash, last_valid_block_height | typed | | `GetBlockHeight` | `commitment?` | block_height | typed | | `GetSlot` | `commitment?` | slot | typed | | `IsBlockhashValid` | blockhash + `commitment?` | slot + valid | typed | | `GetVersion` | vide | version | opaque string bornée | Les unary ne remplacent pas les méthodes HTTP équivalentes : ce sont des capacités du backend Yellowstone et restent séparées des wrappers JSON-RPC HTTP existants. ## 10. Replay, reconnexion et continuité Le changelog upstream contient deux signaux qui interdisent une promesse simpliste : ```text 2026-07-22 : correction d'un replay blocks from_slot accepté mais reprenant live avec state gap 2026-06-15 : auto-reconnect upstream modifié pour mettre le replay en quarantaine et comparer les blockhashes afin de traiter l'equivocation entre nodes ``` Décision KSP : ```text reconnect automatique oui, borné et KSP-owned resubscribe déterministe oui from_slot oui, sans promesse lossless SubscribeReplayInfo oui, informatif exactly-once non garanti lossless non garanti ordre global sans gap non garanti duplicate possible oui, observable/traité selon scope gap possible oui, observable equivocation node/fork observable quand preuve disponible ``` Observabilité cible : ```text reconnect_count continuity_gap_count duplicate_update_count replay_attempt_count last_requested_from_slot last_observed_slot terminal error code safe ``` Une détection d'equivocation peut nécessiter une preuve de blockhash ; si elle ne peut pas être généralisée proprement à toutes les familles, le plan exige de documenter sa couverture exacte au lieu de l'annoncer globalement. ## 11. Stratégie dépendances — A/B/C ### A. `yellowstone-grpc-client + yellowstone-grpc-proto` Avantages : client prêt, TLS/connect/reconnect déjà implémentés. Inconvénients : - sémantique autoreconnect/replay/dedup upstream importée implicitement ; - davantage de dépendances et types upstream ; - risque de fuite de types/client brut dans l'API KSP ; - contrôle moindre sur redaction, backpressure et lifecycle. **Décision : non retenue comme stratégie principale.** Le client reste une référence et peut servir ponctuellement à vérifier le wire dans les tests/outils si nécessaire, sans devenir contrat public. ### B. `yellowstone-grpc-proto + client KSP autour de tonic` Avantages : - proto publié Apache-2.0, pas de copie vendored ; - wire officiel généré disponible ; - Tonic 0.14 aligné avec l'écosystème HTTP/2 moderne déjà présent ; - KSP garde reconnect/backpressure/errors/redaction ; - types upstream cachés derrière les DTOs KSP ; - `solana-pubkey` reste dans la même major actuelle. **Décision : stratégie cible retenue.** Matérialisation réalisée en `pre.002` : ```text yellowstone-grpc-proto ^12.6 root : default-features = false ; Transport : .workspace = true sans feature tonic ^0.14 root : default-features = false ; Transport : features = ["channel"] yellowstone-grpc-client absent prost/prost-types pas de dépendance KSP directe tonic-prost pas de dépendance KSP directe en pre.002 tokio-stream pas ajouté futures-util dépendance existante inchangée ``` Le choix est volontairement plus étroit que le forecast initial : `pre.002` matérialise les messages wire publiés et le channel HTTP/2 lazy, mais **pas encore le client RPC généré, TLS, metadata ou compression**. Les éventuelles features/dependencies supplémentaires doivent être justifiées par `pre.003` et vérifiées par `cargo tree`; elles ne sont pas activées par anticipation. ### C. proto/génération KSP minimale bornée Avantage : contrôle maximum du code généré. Inconvénients : copie/licence/synchronisation du proto, `build.rs`, protoc et dette de suivi plus forte. **Décision : reportée/fallback uniquement si B bloque une exigence KSP démontrée.** ## 12. Architecture publique cible ### 12.1 Séparation des backends et des niveaux Yellowstone ```text HTTP TransportSettings / EndpointClient / pool HTTP existants WebSocket engine WsSession actor partagé Solana standard WS SolanaStandardWsSession Helius LaserStream WS HeliusLaserStreamWsSession Yellowstone gRPC engine nouveau runtime/session physique partagé Solana Yellowstone standard façade typed standard sur ce moteur PublicNode Yellowstone première intégration provider sur standard future providers adapters/capabilities pouvant réutiliser, restreindre ou étendre le standard ``` Cette structure reprend le principe validé par `0.2.7`/`0.2.8` : **le moteur physique n'est jamais recopié par provider**. En revanche, l'intégration provider doit pouvoir exprimer un sous-ensemble du standard, des overrides de comportement ou des extensions wire réelles ; l'équivalence complète avec N2 n'est jamais supposée. Interdictions : ```text pas de WsProtocolKind pour gRPC pas de WsEndpointSettings réutilisé pas de WsSession déguisée pas de client Tonic brut réexporté pas de second actor Yellowstone par provider pas de façade provider vide uniquement pour renommer le même protocole ``` ### 12.2 Noms et ownership Noms cibles, affinables sans casser le principe : ```text # N1 — moteur Yellowstone matérialisé en pre.002 YellowstoneGrpcEndpointUrl YellowstoneGrpcProviderName YellowstoneGrpcClusterName YellowstoneGrpcReconnectSettings YellowstoneGrpcEndpointSettings YellowstoneGrpcSessionSettings YellowstoneGrpcTransportSettings YellowstoneGrpcChannel # channel Tonic lazy privé, sans I/O réseau en pre.002 # N1 — étapes ultérieures YellowstoneGrpcSession YellowstoneSubscriptionHandle # N2 — standard Solana Yellowstone SolanaYellowstoneGrpcSession # façade candidate, si le gate API confirme ce nom YellowstoneSubscribeRequest / filters KSP YellowstoneUpdate / typed update projections # N3 — provider provider descriptor/capabilities ouverts standard capabilities supportées / restreintes explicitement provider extensions typed si nécessaires provider auth/metadata/compression/replay/lifecycle policy PublicNode integration/profile/canaries PublicNode-specific facade seulement si une différence réelle le justifie ``` Le backend wire Tonic/Prost reste privé. Tous les types publics nécessaires sont réexportés au crate root conformément aux règles KSP. Le provider et le protocole restent deux axes distincts : `PublicNode` décrit **où/comment et avec quelles capabilities** on exécute Yellowstone. Si une capacité provider est strictement standard, elle réutilise N2 ; si elle diverge, N3 porte explicitement cette divergence. ### 12.3 Metadata/auth provider-neutral Transport reçoit : ```text metadata publique bornée metadata sensible via wrapper opaque/redacted ``` Il ne connaît : ```text aucun nom KSP_SECRET_* aucun std::env aucun header PublicNode/OrbitFlare/Helius hardcodé comme contrat standard ``` Les clés metadata sont validées avant I/O ; les valeurs sensibles ne sont jamais dans `Debug`, `Display`, `KspError`, logs ou snapshots. ## 13. Config V3 cible Le schéma V2 actuel est fermé et possède : ```text profiles[].endpoints profiles[].ws_endpoints ``` Ajouter gRPC dans V2 ferait évoluer silencieusement une shape fermée. Le gate retient donc **une V3 explicite**, tout en conservant V1/V2 backward-readable. Shape conceptuelle cible : ```text format_version = 3 globals.grpc_defaults profiles[].grpc_endpoints[] ``` Chaque endpoint gRPC doit pouvoir porter au minimum : ```text name enabled provider descriptif cluster descriptif url metadata publique optionnelle secret_metadata optionnelle session/runtime overrides bornés optionnels ``` Règle de sensibilité : - `metadata` ne contient que des valeurs non secrètes ; - `secret_metadata` est une classe séparée ; - Config résout les placeholders et exige une provenance/sensibilité secret appropriée avant mapping ; - Transport reçoit une valeur opaque/redacted et ne sait pas quel env l'a produite. `grpc_defaults` porte les defaults génériques utiles : ```text connect timeout unary timeout close timeout max inbound/outbound message size request/update channel capacities max logical filter groups/names reconnect attempts/backoff ``` La forme JSON exacte et les bornes sont matérialisées en `pre.010`, mais **la décision V3 + `grpc_endpoints` séparés + metadata publique/secrète séparée est fermée par `pre.001`**. ## 14. Audit fournisseurs gRPC gratuits et durables L'objectif n'est pas de sélectionner un SDK provider mais de disposer de smokes accessibles sans abonnement payant éphémère. ### 14.1 PublicNode / Allnodes — priorité 1 PublicNode annonce explicitement des endpoints « free-est » et liste pour Solana : ```text Mainnet: Yellowstone GRPC Testnet: GRPC ``` Endpoint Mainnet affiché officiellement au gate : ```text solana-yellowstone-grpc.publicnode.com:443 ``` PublicNode est un service soutenu/opéré par Allnodes dans l'écosystème actuel ; il ne faut pas modéliser « PublicNode » et « Allnodes » comme deux protocoles Yellowstone distincts. Décision `0.2.9` : ```text PublicNode = première intégration provider concrète du moteur Yellowstone PublicNode Mainnet = premier environnement live opt-in sans secret PublicNode Testnet = second cluster du même provider si endpoint exact confirmé live provider/capabilities/profile explicitement représentés aucun second moteur/actor/session physique façade PublicNode spécialisée seulement si une différence réelle est démontrée Allnodes n'est pas modélisé comme un protocole distinct ``` La page officielle confirme l'existence de Testnet GRPC, mais le hostname exact n'est pas figé dans ce gate tant qu'il n'a pas été confirmé depuis la surface officielle/live. Il sera vérifié avant ajout d'un profil committé. Sources : ```text https://publicnode.com/ https://solana-yellowstone-grpc.publicnode.com/ ``` ### 14.2 OrbitFlare — priorité 2 Le pricing officiel courant annonce pour le plan Free : ```text $0/mo 10 RPS 1 TPS gRPC Access = Devnet only Credit Limits = Unlimited ``` Cela répond au besoin « gratuit durable » mieux qu'un trial de quelques jours, mais nécessite un compte/credential. Décision de séquence : ```text OrbitFlare = release provider dédiée 0.2.10 Devnet Free = cible live prioritaire de cette release auth/capabilities/limites = auditées comme delta provider N3 réutilisation de N2 seulement pour les capacités réellement compatibles aucun OrbitFlareGrpc* public vide si aucune divergence de contrat ne le justifie ``` Source : ```text https://orbitflare.com/pricing ``` ### 14.3 Helius LaserStream gRPC — provider planifié après OrbitFlare Helius reste volontairement hors `0.2.9` et `0.2.10`. Sa release dédiée `0.2.11` devra auditer son delta réel avec Yellowstone upstream : auth, endpoints, replay, reconnect/continuity, capacités supplémentaires ou restrictions, et toute extension wire éventuelle. La compatibilité Yellowstone annoncée ne vaut pas preuve d'équivalence complète. ### 14.4 TODO/IDEAS — autres providers non planifiés Aucune version n'est réservée actuellement pour les providers suivants : ```text TODO eRPC — réauditer accès, auth/IP policy, capabilities et éventuels produits Burst/Shred séparés TODO Triton — réauditer upstream vs extensions Triton, notamment Deshred et évolutions futures TODO Alchemy — réauditer capabilities, auth, replay et limites du produit Yellowstone TODO QuickNode — réauditer auth, compression, from_slot, filtres et limites par plan TODO Chainstack — réauditer add-on, networks, auth et capabilities IDEAS Tatum — accès borné par lifetime credits ; intérêt secondaire IDEAS Shyft — réauditer seulement si gRPC durable devient accessible IDEAS Solinfra — free tier + Yellowstone annoncés mais entitlement gRPC gratuit non confirmé IDEAS NodeFlare — réauditer seulement si offre Yellowstone gratuite durable apparaît ``` Ces entrées n'ont **aucun numéro de release**, aucun forecast et aucun engagement d'implémentation. Elles ne sont reprises dans la séquence active que sur décision explicite ultérieure. Bitquery/CoreCast reste hors de cette file Yellowstone tant que son protocole n'est pas Yellowstone standard. ## 15. Smoke ownership Le smoke live reste opt-in et n'autorise aucune violation architecturale. Hiérarchie cible : ```text 1. Transport pur programmatic -> PublicNode Mainnet, sans secret 2. Transport pur programmatic -> PublicNode Testnet, si endpoint exact confirmé 3. Config V3 -> Transport -> PublicNode profile, si Config est matérialisée dans 0.2.9 OrbitFlare et Helius sont validés dans leurs releases dédiées. Les autres providers ne font l'objet d'aucun smoke planifié tant qu'ils restent en TODO/IDEAS. 4. Tatum Mainnet authentifié, opérateur-only si utile ``` Le smoke 1/2 peut vivre dans `ksp-onchain-transport-lib/tests` car il construit ses settings programmatiquement et ne teste que Transport. Le smoke 3 ne doit pas être ajouté à `ksp-config-lib` par facilité. Si aucune surface d'intégration dédiée n'existe encore, il peut rester une procédure opérateur/documentée ou être placé sur une surface de composition déjà légitime ; le plan doit revalider l'owner au moment de `pre.010/pre.011`. Aucun secret provider n'est versionné. ## 16. Threat model et bornes ### 16.1 Secrets / diagnostics Menaces : ```text URI avec credential metadata gRPC sensible Status/message/details provider arbitraires Debug dérivé de requests/filtres TLS/connect errors réémettant URI/metadata ``` Réponse : projections sûres, error codes KSP, contexts allowlistés et redaction testée. ### 16.2 Ressources À borner avant I/O : ```text URL/metadata key/value lengths connect/unary/close timeouts max inbound/outbound message sizes request/update channel capacities nombre de filter groups longueur et unicité des filter names account/owner/include/exclude/required counts memcmp filters + payload size data slices Cuckoo filter dimensions/data size block/account/transaction update payload reconnect attempts/backoff ``` ### 16.3 Backpressure Politique : ```text aucune queue non bornée aucun drop silencieux présenté lossless overflow observable slow logical subscription isolée si possible shutdown déterministe ``` ### 16.4 Lifecycle adversarial Tester au minimum : ```text server half-close client close remote Status malformed/unknown enum oneof absent/inattendu oversized inbound/outbound stream flood mutation de filtres pendant updates late update après mutation/unsubscribe reconnect loop shutdown during reconnect reconnect sur node divergent duplicate/gap après from_slot/replay TLS/certificate failure unary timeout ``` ## 17. Forecast souple recalibré — **15–20 min max par prerelease ; 1 release <= 1 session** Règles de dimensionnement **obligatoires** : ```text chaque prerelease = tranche nominale de 15–20 minutes de travail effectif maximum si une tranche paraît dépasser 20 minutes -> la scinder avant implémentation 0.2.9 complète = doit rester ouvrable et clôturable dans une seule session de chat si la clôture dans la session devient incertaine -> scinder la release avant dette lourde le numéro final des prereleases n'est jamais une deadline ``` Prévision courante : ```text pre.001 DONE — audit upstream/service/proto + providers gratuits + licences/deps + architecture + threat model + sizing budget : 15–20 min nominal ; preuve : plan + matrice + stratégie B + forecast recalibré pre.002 IMPLEMENTED — moteur Yellowstone : proto/dependencies + settings/errors + channel minimal budget : 15–20 min ; preuve locale : audit statique KSP clean + redaction/API canaries ajoutés ; compile/tests/cargo tree = gate opérateur pre.003 moteur Yellowstone : TLS/metadata générique + fixture locale + 7 unary RPCs budget : 15–20 min ; preuve : connect/TLS/timeouts/Status safe + wire unary exact pre.004 standard Solana : Subscribe foundation + maps/commitment/ping/from_slot/data slices/bounds budget : 15–20 min ; preuve : omitted/empty/oneof exact + rejets avant I/O pre.005 standard Solana : Accounts + Slots filters/updates budget : 15–20 min ; preuve : fixtures exactes + enum/optional/malformed/adversarial pre.006 standard Solana : Transactions + transaction_status budget : 15–20 min ; preuve : include/exclude/required/Cuckoo/token expansion + tx/meta pre.007 standard Solana : Blocks + block_meta + entry budget : 15–20 min ; preuve : counts/arrays/optional/oneof/payload bounds pre.008 moteur partagé : bidi mutation + Ping/Pong + half-close + backpressure + shutdown budget : 15–20 min ; preuve : actor/session local + bounded queues + cleanup déterministe pre.009 moteur partagé : reconnect/resubscribe + from_slot/ReplayInfo + gaps/duplicates budget : 15–20 min ; preuve : reconnect local déterministe + aucune promesse lossless pre.010 Config V3 + séparation protocol/provider + profils PublicNode Mainnet/Testnet budget : 15–20 min ; preuve : V1/V2 backward + schema/mapping/redaction + Config -> Transport pre.011 intégration PublicNode + smokes live + compliance + docs finales + prompt 0.2.10 OrbitFlare budget : 15–20 min ; preuve : Mainnet/Testnet opt-in + HTTP 52/14 + WS 18/18 + Helius + cargo graphs + workspace final rel.001 publication stable stricte ``` Prévision : **11 prereleases**, soit environ **165–220 minutes de travail effectif nominal hors temps d'attente des commandes**, compatible avec une session complète. Si une tranche réelle excède son budget ou si `pre.011` ne peut pas raisonnablement fermer la release dans la session, on scinde avant de poursuivre au lieu de prolonger artificiellement `0.2.9`. ### Critères de split Scinder avant dette silencieuse si l'un de ces cas apparaît : 1. `yellowstone-grpc-proto + tonic` impose une incompatibilité avec la Rust stable courante ou un doublon majeur de stack réseau impossible à justifier ; 2. les DTOs transactions/blocs exigent une réexposition massive des types upstream ou une réimplémentation disproportionnée ; 3. l'upstream modifie encore matériellement le proto pendant la release ; 4. le replay/reconnect devient un sous-système plus grand que la foundation ; 5. PublicNode exige finalement un comportement provider-specific assez large pour dépasser la session ; 6. toute prerelease dépasse le budget nominal de 20 minutes sans frontière claire de split. En cas de split, le noyau prioritaire à conserver dans `0.2.9` est : ```text moteur Yellowstone + façade Solana standard + première intégration PublicNode minimale ``` et le reste est replanifié explicitement ; aucune capacité n'est abandonnée silencieusement. ## 18. Fichiers attendus par tranche Cibles réelles ouvertes par `pre.002`, puis cibles probables suivantes : ```text # pre.002 crates/ksp-onchain-transport-lib/src/grpc_settings.rs crates/ksp-onchain-transport-lib/src/grpc_channel.rs crates/ksp-onchain-transport-lib/unit_tests/grpc_settings.rs crates/ksp-onchain-transport-lib/unit_tests/grpc_channel.rs # pre.003+ crates/ksp-onchain-transport-lib/src/grpc_session.rs crates/ksp-onchain-transport-lib/src/grpc_protocol.rs crates/ksp-onchain-transport-lib/src/grpc_subscribe.rs crates/ksp-onchain-transport-lib/src/grpc_updates.rs crates/ksp-onchain-transport-lib/src/grpc_unary.rs unit_tests/ correspondants tests/public_api.rs tests/release_completeness.rs tests/yellowstone_grpc_*_smoke.rs crates/ksp-config-lib/src/transport.rs config/std.transport.json config/schemas/std.transport.schema.json .env.example si des variables provider committées sont introduites ``` Les noms exacts restent soumis aux règles de structure du code réel ; ce plan ne force pas un fichier par concept si une composition plus claire apparaît. ## 19. Gates de validation Après chaque changement Rust : ```bash cargo fmt --all python3 scripts/audit_rust_workspace_rules.py cargo check --workspace cargo clippy --workspace --all-targets ``` Tests ciblés : ```bash cargo test -p ksp-onchain-transport-lib cargo test -p ksp-config-lib # seulement si Config modifiée ``` À la fermeture technique d'une prerelease : ```bash cargo test --workspace ``` Après ajout/modification de la stack gRPC : ```bash cargo tree -p ksp-onchain-transport-lib cargo tree -p ksp-onchain-transport-lib --duplicates cargo tree --duplicates ``` Inspecter en particulier : ```text yellowstone-grpc-proto tonic / tonic-prost prost / prost-types bytes / http / hyper / hyper-util tower rustls / tokio-rustls solana-* transitifs ``` ## 20. Conditions de clôture `0.2.9` ne devient stable que si : ```text inventaire service/proto courant réconcilié SubscribeDeshred explicitement exclu/classifié 7 unary RPCs retenus validés Subscribe standard retenu sans perte arbitraire 9 update variants traitées provider-neutral API sans raw client escape hatch metadata/secrets redacted resource bounds et backpressure testés reconnect/from_slot/replay documentés sans promesse lossless Config V3 backward V1/V2 si Config intégrée PublicNode intégration provider matérialisée sans duplication du moteur PublicNode interop Mainnet validée opt-in ou impossibilité externe documentée PublicNode Testnet validé si endpoint live confirmé, sinon raison documentée OrbitFlare/Helius absents du runtime 0.2.9 hors documentation de séquence ; autres providers uniquement TODO/IDEAS HTTP 52+14 non régressé standard WS 18/18 non régressé Helius WS non régressé cargo graphs inspectés README/USAGE synchronisés matrice `012` fermée prompt 0.2.10 OrbitFlare prêt workspace final vert ``` ## 21. Releases suivantes recalibrées Le gate `pre.001-fix.002` reprend la logique WebSocket : moteur/standard d'abord, puis uniquement les providers effectivement retenus pour implémentation. ```text 0.2.9 moteur Yellowstone + Solana standard + PublicNode 0.2.10 OrbitFlare Yellowstone gRPC 0.2.11 Helius LaserStream gRPC 0.2.12 off-chain price transport 0.2.13 Price Desk + intégration prix Wallet Desk 0.2.14 interface/wire foundation 0.2.15 program-api foundation ``` Les autres providers Yellowstone — eRPC, Triton, Alchemy, QuickNode, Chainstack, Tatum, Shyft, Solinfra, NodeFlare et autres — restent en **TODO/IDEAS non numérotés**. Ils ne doivent pas déplacer la séquence active tant qu'une décision explicite d'implémentation n'est pas prise. Pour toute intégration provider future, la règle reste : N1 n'est jamais dupliqué ; N2 est réutilisé seulement là où le provider est réellement compatible ; N3 exprime explicitement les restrictions, overrides et extensions.