# Plan `0.2.9` — moteur Yellowstone gRPC + standard Solana + PublicNode > **Statut : `0.2.9-pre.001-fix.001` — gate audit/sizing corrigé. `0.2.9` est bornée à un moteur client Yellowstone partagé, une façade Solana Yellowstone standard et une première intégration concrète PublicNode. Les autres providers Yellowstone sont sortis de la release et planifiés séparément. 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 ni du wire standard ``` 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. Sont explicitement exclus de `0.2.9` : ```text SubscribeDeshred et pré-exécution/deshred OrbitFlare provider integration Helius LaserStream gRPC provider integration eRPC provider integration Tatum/Triton/Chainstack/Shyft/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 ``` Les providers suivants sont **des releases ultérieures**, comme Helius LaserStream WebSocket l'a été après le moteur WebSocket standard. Ils réutiliseront N1/N2 et n'ajouteront une façade spécialisée que lorsqu'une différence d'authentification, de capabilities, de wire, de keepalive, de replay ou de lifecycle le nécessite. ## 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. Éléments build à vérifier en `pre.002` : ```text proto crate crate publiée/pré-générée ; pas de vendoring de .proto KSP client KSP autour de Tonic features client/TLS minimales protoc/build.rs aucun outil système ajouté sauf besoin démontré ``` 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 attendue en `pre.002` : ```text yellowstone-grpc-proto ^12.6 workspace dependency, features minimales tonic ^0.14 workspace dependency, features client/TLS minimales prost/prost-types pas de direct dependency KSP sauf besoin démontré tokio-stream/futures seulement si nécessaire et sans doublon gratuit ``` L'exacte feature set sera déterminée par compilation et `cargo tree`, pas par anticipation documentaire. ### 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/facades séparés seulement si différence réelle ``` Cette structure reprend le principe validé par `0.2.7`/`0.2.8` : **le moteur physique n'est jamais recopié par provider**. 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 YellowstoneGrpcEndpointUrl YellowstoneGrpcEndpointSettings YellowstoneGrpcSessionSettings YellowstoneGrpcTransportSettings 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 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** on exécute Yellowstone standard, pas un nouveau protocole. ### 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/Tatum 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 `0.2.9` : ```text OrbitFlare Devnet = smoke live opt-in secondaire auth = via generic secret metadata Config -> Transport aucun OrbitFlareGrpc* public aucun header provider hardcodé avant vérification exacte de la doc/live ``` Source : ```text https://orbitflare.com/pricing ``` ### 14.3 Tatum — candidat tertiaire, non gate Tatum documente un endpoint Yellowstone Solana Mainnet et un plan Free utilisable sans abonnement payant, mais le plan courant impose : ```text 3 RPS 100K lifetime credits 5 subscriptions ``` Le caractère « forever » du plan n'en fait donc pas une ressource illimitée dans le temps : le quota de crédits est lifetime. Décision : **candidat manuel tertiaire**, utile pour interop Mainnet authentifiée, mais pas dépendance du gate `0.2.9`. Sources : ```text https://docs.tatum.io/reference/solana-grpc https://tatum.io/pricing ``` ### 14.4 Fournisseurs vérifiés mais non retenus comme gratuits gRPC État courant vérifié : ```text Helius Free: pas de LaserStream gRPC ; Devnet à partir de Developer, Mainnet Business Shyft Free: No gRPC Access Alchemy Yellowstone gRPC: PAYG ou Enterprise requis QuickNode Yellowstone gRPC: Scale/Business ou add-on payant Chainstack Yellowstone gRPC: add-on payant à partir de 49 USD/mois, Growth+ ERPC Geyser gRPC payant ; seulement trial 1 jour sur le plan Standard NodeFlare endpoint Yellowstone publié, mais plan Yellowstone à forfait mensuel Bitquery CoreCast gRPC n'est pas Yellowstone ; accès stream gratuit non garanti et offre publique payante/trial ``` Candidat non validé comme gratuit durable : ```text Solinfra site public = free tier + Yellowstone annoncés, mais entitlement gRPC du free tier non explicite ``` Solinfra pourra être revalidé en `pre.011` si une grille publique ou le dashboard confirme un droit Yellowstone durable à 0 USD. Triton et d'autres providers peuvent également être réaudités si leur offre change, mais aucun autre accès Yellowstone gratuit durable n'a été confirmé avec une preuve publique suffisante pendant ce gate. ## 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 les providers authentifiés sont validés dans leurs releases dédiées. 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 moteur Yellowstone : proto/dependencies + settings/errors + channel minimal budget : 15–20 min ; preuve : features minimales + compile/tests + redaction + cargo tree 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 probables, sans imposer artificiellement le découpage source : ```text crates/ksp-onchain-transport-lib/src/grpc_settings.rs 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/eRPC absents du runtime 0.2.9 hors documentation de séquence 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.001` reprend la logique WebSocket : moteur/standard d'abord, providers ensuite, un provider par release lorsque son intégration apporte un delta réel. ```text 0.2.9 moteur Yellowstone + Solana standard + PublicNode 0.2.10 OrbitFlare Yellowstone gRPC 0.2.11 Helius LaserStream gRPC 0.2.12 eRPC Yellowstone gRPC, conditionné à un accès exploitable et à un delta provider réel 0.2.13 off-chain price transport 0.2.14 Price Desk + intégration prix Wallet Desk 0.2.15 interface/wire foundation 0.2.16 program-api foundation ``` La numérotation `0.2.10+` reste réauditable au gate de chaque release : un provider qui n'ajoute finalement qu'une URL interchangeable sans contrat propre ne doit pas provoquer une façade vide ni une release artificielle.