63 KiB
Plan 0.2.9 — moteur Yellowstone gRPC + standard Solana + PublicNode
Statut :
0.2.9-pre.009est fonctionnellement verte sur gate opérateur (Transport 379 unit + 48 public API + 42 completeness + 4 doctests, workspace PASS), mais Clippy signale deux warnings d’hygiène.0.2.9-pre.009-fix.001est candidate pour les supprimer sans modifier le protocole ni le lifecycle ; reconnect/replay restentpre.010.
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 :
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 :
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 :
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 :
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 :
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 :
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 :
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: falseet distingueendpoints/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 :
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 :
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 :
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 :
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 :
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 :
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 :
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é :
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 :
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 :
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 :
licence par défaut du repository = AGPL-3.0-only
mais LICENSING.md affecte explicitement Apache-2.0 aux sous-arbres :
examples/
yellowstone-grpc-client/
yellowstone-grpc-client-nodejs/
yellowstone-grpc-proto/
Conséquence du gate :
- dépendre de la crate publiée
yellowstone-grpc-protoest 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
.protodans 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 :
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 après matérialisation pre.003 :
yellowstone-grpc-proto ^12.6 runtime : default-features = false, aucune feature `tonic`
dev/test : feature `tonic` uniquement pour GeyserServer de fixture
tonic ^0.14 runtime : channel + tls-aws-lc + tls-webpki-roots
dev/test : codegen + server ajoutés explicitement
http ^1.5 direct KSP pour PathAndQuery unary sans constructeur panic
tonic-prost ^0.14 direct KSP pour ProstCodec ; sa dépendance Tonic désactive les defaults
yellowstone-grpc-client absent
prost/prost-types aucune dépendance KSP directe
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
La séparation reste intentionnelle : les messages Protobuf officiels sont consommés sans activer le client généré Yellowstone dans le runtime. La feature tonic du proto est réservée au graphe dev/test pour matérialiser le serveur Geyser de fixture. KSP utilise le dispatcher tonic::client::Grpc + tonic-prost::ProstCodec derrière sa façade N2 et conserve ainsi ses propres timeouts, redactions et erreurs.
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
account[]
owner[]
filters[]
nonempty_txn_signature?
cuckoo_accounts_filter?
Filtres account :
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
filter_by_commitment?
interslot_updates?
SlotStatus courant :
processed
confirmed
finalized
first_shred_received
completed
created_bank
dead
7.3 Transactions / transaction_status
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
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
commitment? Processed | Confirmed | Finalized
accounts_data_slice offset + length
ping? id
from_slot? u64
KSP applique 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. pre.004 matérialise les bornes communes suivantes :
filter groups nommés, total <= 1024 sur les sept maps
filter name non vide, trim exact, sans caractère de contrôle, <= 128 octets
filter names uniques globalement entre les sept maps
accounts_data_slice count <= 128
accounts_data_slice length <= 64 MiB
offset + length aucun overflow u64
Les bornes Accounts sont matérialisées en pre.005; les bornes include/exclude/required et Cuckoo propres aux Transactions/Blocks restent dans pre.007–008.
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 :
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 :
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 :
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 :
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-pubkeyreste dans la même major actuelle.
Décision : stratégie cible retenue.
Matérialisation après pre.003 :
yellowstone-grpc-proto ^12.6 runtime sans feature ; dev/test feature `tonic` pour le serveur de fixture uniquement
tonic ^0.14 runtime features = ["channel", "tls-aws-lc", "tls-webpki-roots"]
dev/test ajoute ["codegen", "server"]
tonic-prost ^0.14 runtime, ProstCodec bas niveau
http ^1.5 runtime, PathAndQuery borné/interne
yellowstone-grpc-client absent
prost/prost-types pas de dépendance KSP directe
tokio-stream pas ajouté directement
futures-util dépendance existante réutilisée par la fixture Stream
pre.003 n'active toujours ni client Yellowstone upstream ni compression. Les sept unary passent par une façade KSP au-dessus du channel N1 ; la surface GeyserServer générée n'existe que dans les tests pour prouver le wire exact localement. Le graphe Cargo doit être réinspecté après application parce que les features TLS et les deux dépendances directes http/tonic-prost changent le graphe runtime.
Le premier gate opérateur de pre.002 confirme l'alignement de versions utile : Tonic 0.14.6 réutilise http 1.5, hyper 1.11, hyper-util 0.1, tower 0.5 et bytes 1.12 déjà présents ; yellowstone-grpc-proto unifie solana-pubkey en 4.3.0. Les occurrences Prost 0.14.4 visibles dans cargo tree --duplicates correspondent aux contextes runtime/build de la même version, notamment prost-build/tonic-prost-build, et ne constituent pas une seconde génération de version à corriger.
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
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 :
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 :
# 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<T>
# 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 :
metadata publique bornée
metadata sensible via wrapper opaque/redacted
Il ne connaît :
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 :
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 :
format_version = 3
globals.grpc_defaults
profiles[].grpc_endpoints[]
Chaque endpoint gRPC doit pouvoir porter au minimum :
name
enabled
provider descriptif
cluster descriptif
url
metadata publique optionnelle
secret_metadata optionnelle
session/runtime overrides bornés optionnels
Règle de sensibilité :
metadatane contient que des valeurs non secrètes ;secret_metadataest 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 :
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.011, 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 :
Mainnet: Yellowstone GRPC
Testnet: GRPC
Endpoint Mainnet affiché officiellement au gate :
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 :
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 :
https://publicnode.com/
https://solana-yellowstone-grpc.publicnode.com/
14.2 OrbitFlare — priorité 2
Le pricing officiel courant annonce pour le plan Free :
$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 :
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 :
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 :
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 :
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.011/pre.012.
Aucun secret provider n'est versionné.
16. Threat model et bornes
16.1 Secrets / diagnostics
Menaces :
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 :
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 :
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 :
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 :
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 :
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 DONE — moteur Yellowstone : proto/dependencies + settings/errors + channel minimal
budget : 15–20 min ; gate final fix.002 : fmt/audit/check/Clippy + Transport 346/42/35/4 + dependency canary + workspace PASS
pre.003 DONE — moteur TLS/metadata + façade N2 unary + fixture locale + 7 unary RPCs
budget : 15–20 min ; gate final fix.001 : fmt/audit/check/Clippy/workspace PASS + graphes Cargo inspectés
pre.004 DONE — standard Solana : Subscribe foundation + maps/commitment/ping/from_slot/data slices/bounds
budget : 15–20 min ; gate final fix.001 : fmt/audit/check/Clippy/workspace PASS sans warning + Transport 359/44/37/4
pre.005 DONE — standard Solana : Accounts + Slots filters/updates
budget : 15–20 min ; gate final fix.001 : fmt/audit/check/Clippy/workspace PASS sans warning + Transport 364/45/38/4
pre.006 DONE — structure Transport : namespace privé HTTP explicite
budget : 15–20 min ; gate opérateur final PASS 364/45/39/4 + workspace
pre.007 DONE — standard Solana : Transactions + transaction_status
budget : 15–20 min ; preuve : include/exclude/required/Cuckoo/token expansion + tx/meta + TransactionConfig V1
pre.008 DONE — standard Solana : Blocks + block_meta + entry
budget : 15–20 min ; gate final fix.001 : fmt/audit/check/Clippy/workspace PASS sans warning + Transport 370/47/41/4
pre.009 FIX.001 CANDIDATE — moteur partagé : bidi mutation + Ping/Pong + half-close + backpressure + shutdown
budget : 15–20 min ; gate fonctionnel 379/48/42/4 + workspace PASS ; fix de deux warnings Clippy
pre.010 moteur partagé : reconnect/resubscribe + from_slot/ReplayInfo + gaps/duplicates
budget : 15–20 min ; preuve : reconnect local déterministe + aucune promesse lossless
pre.011 Config V3 + séparation protocol/provider + profils PublicNode Mainnet/Testnet
budget : 15–20 min ; preuve : V1/V2 backward + schema/mapping/redaction + Config -> Transport
pre.012 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 : 12 prereleases, soit environ 180–240 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.012 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 :
yellowstone-grpc-proto + tonicimpose une incompatibilité avec la Rust stable courante ou un doublon majeur de stack réseau impossible à justifier ;- les DTOs transactions/blocs exigent une réexposition massive des types upstream ou une réimplémentation disproportionnée ;
- l'upstream modifie encore matériellement le proto pendant la release ;
- le replay/reconnect devient un sous-système plus grand que la foundation ;
- PublicNode exige finalement un comportement provider-specific assez large pour dépasser la session ;
- 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 :
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 :
# 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_unary.rs
crates/ksp-onchain-transport-lib/unit_tests/grpc_unary.rs
crates/ksp-onchain-transport-lib/src/grpc_channel.rs
crates/ksp-onchain-transport-lib/src/grpc_settings.rs
# pre.004
crates/ksp-onchain-transport-lib/src/grpc_subscribe.rs
crates/ksp-onchain-transport-lib/unit_tests/grpc_subscribe.rs
tests/public_api.rs
tests/release_completeness.rs
# pre.005+
crates/ksp-onchain-transport-lib/src/grpc_session.rs
crates/ksp-onchain-transport-lib/src/grpc_updates.rs
unit_tests/ correspondants
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 :
cargo fmt --all
python3 scripts/audit_rust_workspace_rules.py
cargo check --workspace
cargo clippy --workspace --all-targets
Tests ciblés :
cargo test -p ksp-onchain-transport-lib
cargo test -p ksp-config-lib # seulement si Config modifiée
À la fermeture technique d'une prerelease :
cargo test --workspace
Après ajout/modification de la stack gRPC :
cargo tree -p ksp-onchain-transport-lib
cargo tree -p ksp-onchain-transport-lib -e features
cargo tree -p ksp-onchain-transport-lib --duplicates
cargo tree --duplicates
Inspecter en particulier :
yellowstone-grpc-proto
tonic / tonic-prost
prost / prost-types
bytes / http / hyper / hyper-util
tower
rustls / tokio-rustls
features Tonic : channel/TLS runtime ; codegen/server dev ; pas de router/gzip/zstd KSP
solana-* transitifs
19.1 Gate opérateur final pre.002-fix.002
Preuve opérateur du 2026-08-24 :
cargo fmt --all PASS
python3 scripts/audit_rust_workspace_rules.py PASS / clean
cargo check --workspace PASS
cargo clippy --workspace --all-targets PASS
Transport unit PASS 346/346
Transport public_api PASS 42/42
Transport release_completeness PASS 35/35
Transport doctests PASS 4/4
Core workspace_dependencies PASS 3/3
cargo test --workspace PASS ; seuls smokes/bench diagnostics explicitement ignored
pre.002 est donc fermée. Les graphes Cargo fournis au premier gate restent valides pour son dependency set ; pre.003 doit les relancer parce qu'elle active TLS et ajoute http/tonic-prost.
19.2 Gate source pre.003
Le premier gate opérateur de pre.003 confirme que la surface fonctionnelle compile et que les tests sont verts, mais Clippy isole 11 diagnostics implicit_return exclusivement dans unit_tests/grpc_unary.rs : neuf sur les méthodes transformées par #[tonic::async_trait] malgré des retours explicites dans leurs corps, et deux sur des closures and_then. pre.003-fix.001 applique une exception de lint localisée à l'implémentation fixture générée par la macro et rend explicites les deux retours de closures. Aucun code runtime N1/N2 n'est modifié.
La candidate matérialise :
N1 : connect() réel + TLS WebPKI/rustls + metadata ASCII publique/secrète redacted
N2 : exactement 7 unary Yellowstone standard via dispatcher Tonic privé
fixture : GeyserServer local dev-only, metadata + commitment + timeout + Status hostile
OUT : Subscribe, SubscribeDeshred, PublicNode, Config V3, reconnect/stream lifecycle
Le runtime n'active pas la feature tonic de yellowstone-grpc-proto; cette feature et tonic codegen/server sont réservées au graphe dev/test de la fixture. Le gate Cargo opérateur reste requis avant commit.
19.3 Gate opérateur final pre.004-fix.001
Preuve opérateur du 2026-08-24 :
cargo fmt --all PASS
python3 scripts/audit_rust_workspace_rules.py PASS / clean
cargo check --workspace PASS sans warning gRPC pre.004
cargo clippy --workspace --all-targets PASS sans warning gRPC pre.004
Transport unit PASS 359/359
Transport public_api PASS 44/44
Transport release_completeness PASS 37/37
Transport doctests PASS 4/4
cargo test --workspace PASS ; seuls smokes/bench diagnostics explicitement ignored
pre.004 est donc fermée. Aucun changement de dépendance n'ayant eu lieu depuis pre.003, les graphes Cargo déjà inspectés restent l'autorité du dependency set.
19.4 Gate source pre.005 — Accounts + Slots
La candidate matérialise exactement :
Accounts request : account[]/owner[]/filters[]/nonempty_txn_signature?/cuckoo_accounts_filter?
Account predicates : memcmp bytes/base58/base64, datasize, token_account_state, lamports eq/ne/lt/gt
Slots request : filter_by_commitment? + interslot_updates?
Account update : filters/created_at + account info + slot + is_startup
Slot update : filters/created_at + slot + parent? + 7 SlotStatus + dead_error?
Les bornes provider-neutral KSP de cette tranche couvrent notamment les sélecteurs Accounts, predicates, memcmp, Cuckoo, taille account-data, noms de filtres d'update, timestamp nanos, signature fixe 64 octets et dead_error. Les Debug KSP n'exposent ni pubkeys sélectionnées, ni payload memcmp/Cuckoo/account-data, ni texte dead_error.
Les conversions protobuf et décodeurs update restent sous #[cfg(test)] jusqu'à pre.009, car aucun stream runtime ne les consomme encore. Cette décision évite du faux dead_code sans créer une seconde implémentation : les mêmes helpers seront remis en runtime au moment de l'ouverture bidi.
OUT de pre.005 : Transactions/transaction_status, Blocks/block_meta/entry, stream bidi, provider PublicNode, Config V3 et SubscribeDeshred.
Verdict pre.005 : candidate source prête ; fermeture après gate Cargo opérateur.
20. Conditions de clôture
0.2.9 ne devient stable que si :
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.
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.
19.5 pre.005-fix.001 — hygiène warning/Clippy et format documentaire
Le premier gate opérateur de pre.005 confirme la surface fonctionnelle : 364/364 unit, 45/45 public API, 38/38 release-completeness et workspace complet PASS. Les seuls écarts sont quatre constantes utilisées uniquement par les décodeurs #[cfg(test)], une convention to_wire(&self) sur un type Copy, et une closure is_some_and soumise à -D clippy::implicit-return.
| Correction | Traitement | Impact runtime |
|---|---|---|
| quatre constantes de bounds update | #[cfg(test)] |
aucun avant pre.009 |
YellowstoneSubscribeSlotFilter::to_wire |
receiver self |
aucun, helper test-only |
closure dead_error.is_some_and |
return explicite |
aucun |
tableaux 016 et 012 |
reformatage JetBrains RustRover (largeur max + un espace de padding) | documentaire uniquement |
Le reformatage documentaire reproduit le comportement RustRover : largeur calculée sur le contenu le plus large de chaque colonne et exactement un espace de padding de chaque côté du contenu avant les pipes.
Verdict pre.005-fix.001 : correctif minimal prêt ; pre.005 reste ouverte jusqu'à réexécution sans warning de check/Clippy/workspace.
19.6 Gate final pre.005-fix.001
Le second gate opérateur confirme la fermeture complète de pre.005 : fmt, audit Rust, check et Clippy passent sans warning ; Transport passe 364 unit + 45 public API + 38 release-completeness + 4 doctests ; le dependency canary Core passe 3/3 et cargo test --workspace est vert.
Verdict : pre.005 fermée.
20. pre.006 — namespace privé HTTP explicite
Le développement simultané de HTTP, WebSocket et Yellowstone gRPC rend les anciens noms privés client, executor, pool, resilience et settings trop ambigus. Ces cinq modules sont exclusivement propriétaires de la pile HTTP et deviennent donc :
client.rs -> http_client.rs
executor.rs -> http_executor.rs
pool.rs -> http_pool.rs
resilience.rs -> http_resilience.rs
settings.rs -> http_settings.rs
Les unit tests miroirs reçoivent les mêmes noms. Le changement reste privé à la crate : les types publics sont déjà explicitement nommés Http* et leurs chemins au crate root ne changent pas.
Le mini-audit interdit un renommage aveugle des autres modules : rpc_accounts, rpc_blocks, rpc_transactions et rpc_common portent des DTOs/types déjà réutilisés par WebSocket et/ou gRPC ; json_rpc décrit le protocole d'enveloppe ; constants et error sont transverses. Ils conservent donc leur nom actuel.
Cette tranche est volontairement séparée de Transactions afin de respecter le budget 15–20 minutes et d'éviter de combiner un refactor de fichiers avec une nouvelle surface protobuf. L'ancien forecast fonctionnel pre.006–011 est décalé vers pre.007–012 sans changement de contenu.
Gate candidat : audit Rust clean, public API inchangée, cinq anciens modules absents après suppression opérateur, cinq nouveaux modules http_* compilés, release-completeness canary dédié, workspace complet vert.
21. Gate final pre.006 — namespace privé HTTP
Preuve opérateur du 2026-08-24 :
| Gate | Résultat final |
|---|---|
cargo fmt --all |
PASS |
| audit Rust workspace | PASS / clean |
cargo check --workspace |
PASS |
cargo clippy --workspace --all-targets |
PASS |
| Transport unit | 364/364 PASS |
Transport public_api |
45/45 PASS |
Transport release_completeness |
39/39 PASS |
| Transport doctests | 4/4 PASS |
| Core dependency canary | 3/3 PASS |
cargo test --workspace |
PASS |
Les cinq modules privés HTTP et leurs unit tests miroirs sont désormais effectivement nommés http_*. Le canari release_v0_2_9_pre_006_namespaces_unambiguously_http_owned_private_modules passe et les modules partagés rpc_*/json_rpc restent volontairement non préfixés.
Verdict : pre.006 fermée.
22. pre.007 — Transactions + transaction_status candidate
Le proto yellowstone-grpc-proto 12.6.0 est réaudité avant implémentation. SubscribeRequestFilterTransactions contient exactement vote?, failed?, signature?, account_include[], account_exclude[], account_required[], cuckoo_account_include? et token_accounts?. La même structure filtre transactions et transactions_status.
La candidate matérialise :
request filters
vote? / failed?
signature? : Base58 validé et décodé exactement sur 64 octets
account_include[] / account_exclude[] / account_required[]
cuckoo_account_include?
token_accounts? = ALL | BALANCE_CHANGED
updates
transaction : filters + created_at + slot + signature/is_vote/index + transaction + meta
transaction_status : filters + created_at + slot + signature/is_vote/index + error?
solana-storage typed
Transaction / Message / MessageHeader
CompiledInstruction / MessageAddressTableLookup
TransactionConfig V1 (priority_fee/compute_unit_limit/loaded_accounts_data_size_limit/heap_size)
TransactionStatusMeta + TransactionError
InnerInstructions / InnerInstruction
TokenBalance / UiTokenAmount
ReturnData / Reward
loaded writable/readonly addresses
compute_units_consumed? / cost_units?
Les marqueurs inner_instructions_none, log_messages_none et return_data_none sont conservés séparément de leurs payloads. Les erreurs transaction sont des bytes opaques bornés : aucun décodage Program/runtime arbitraire n'est introduit. Les types protobuf upstream restent internes. Les conversions request et les décodeurs update restent #[cfg(test)] jusqu'à l'ouverture du stream runtime en pre.009.
OUT de pre.007 : Blocks/block_meta/entry, stream bidi/Ping-Pong, reconnect/replay, Config V3, PublicNode et SubscribeDeshred.
Gate candidat : audit statique clean ; compilation/Clippy/tests opérateur requis avant fermeture.
23. Gate final pre.007 — Transactions + transaction_status
Preuve opérateur du 2026-08-24 :
| Gate | Résultat final |
|---|---|
cargo fmt --all |
PASS |
| audit Rust workspace | PASS / clean |
cargo check --workspace |
PASS |
cargo clippy --workspace --all-targets |
PASS |
| Transport unit | 367/367 PASS |
Transport public_api |
46/46 PASS |
Transport release_completeness |
40/40 PASS |
| Transport doctests | 4/4 PASS |
| Core dependency canary | 3/3 PASS |
cargo test --workspace |
PASS |
Le gate confirme la projection Transactions complète, incluant TransactionConfig V1 et les marqueurs legacy de TransactionStatusMeta, sans régression HTTP/WS et sans avancer Blocks ou bidi.
Verdict : pre.007 fermée.
24. pre.008 — Blocks + block_meta + entry candidate
Le proto yellowstone-grpc-proto 12.6.0 est réaudité avant implémentation. SubscribeRequestFilterBlocks contient exactement account_include[], include_transactions?, include_accounts?, include_entries? et cuckoo_account_include?. blocks_meta et entry conservent leurs filtres marqueurs vides.
La candidate matérialise :
request filter Blocks
account_include[] ordonné et borné
include_transactions?
include_accounts?
include_entries?
cuckoo_account_include?
SubscribeUpdateBlock
slot / blockhash / parent_slot / parent_blockhash
rewards? + num_partitions?
block_time? / block_height?
executed_transaction_count
transactions[] -> YellowstoneTransactionInfo réutilisé
updated_account_count
accounts[] -> YellowstoneAccountInfo réutilisé
entries_count
entries[] -> YellowstoneEntryInfo
SubscribeUpdateBlockMeta
même metadata sans payloads transaction/account/entry
SubscribeUpdateEntry
slot / index / num_hashes / hash[32]
executed_transaction_count
starting_transaction_index
Les compteurs serveur ne sont volontairement pas comparés aux longueurs des vecteurs : les options include_transactions, include_accounts et include_entries permettent au serveur de rapporter les totaux tout en omettant les payloads correspondants. Les blockhash/parent_blockhash sont validés comme Base58 représentant 32 octets, et les hash d’entrée restent des 32 octets exacts. Debug n’expose aucun hash, account selector, reward pubkey ou payload imbriqué.
Les conversions request protobuf et décodeurs Block/BlockMeta/Entry restent #[cfg(test)] jusqu’à l’ouverture du stream runtime en pre.009. Aucun SubscribeDeshred, provider PublicNode, Config V3, Ping/Pong lifecycle ou reconnect n’entre dans cette tranche.
Gate candidat : audit statique clean ; compilation/Clippy/tests opérateur requis avant fermeture.
25. pre.008-fix.001 — hygiène Clippy de la fixture Blocks
Le premier gate opérateur de pre.008 confirme l'intégralité du contrat Blocks : fmt/audit/check/tests/workspace passent, avec Transport 370/370 unit, 47/47 public API, 41/41 completeness et 4/4 doctests. Clippy termine également avec succès mais signale un unique field_reassign_with_default dans minimal_transaction_info() de la fixture grpc_subscribe.
Le fix remplace la construction TransactionStatusMeta::default() suivie de meta.fee = 5_000 par un initialiseur struct avec fee: 5_000 et ..Default::default(). Aucun allow, aucune API, aucun DTO, aucun wire et aucune logique runtime ne changent.
Gate final : fmt/audit/check/Clippy/workspace PASS sans warning. pre.008-fix.001 est fermée ; le bidi reste strictement pre.009.
26. pre.009 — stream bidi standard + lifecycle borné candidate
pre.009 ouvre pour la première fois le RPC /geyser.Geyser/Subscribe en runtime KSP, sans yellowstone-grpc-client et sans second moteur physique. YellowstoneGrpcChannel::open_standard_subscribe() construit une SolanaYellowstoneGrpcSubscribeSession sur le channel Tonic déjà possédé par N1.
Contrat de la tranche :
request initial validé + taille protobuf bornée
file request mpsc bornée et directement consommée par Tonic
try_update() non bloquant : validation + encoded_len + Full/Closed explicites
file update mpsc bornée ; slow receiver => terminal backpressure overflow
SubscribeUpdate complet : Account/Slot/Transaction/TransactionStatus/Block/Ping/Pong/BlockMeta/Entry
server Ping => réponse automatique ping-only id=1
Pong => update KSP observable
server half-close => terminal normal Ok(None)
client close => drop des senders request + half-close + attente close_timeout
Drop session => signal best-effort de half-close borné
Status/malformed/overflow => terminal Failed avec KspError sûr
inbound/outbound max message sizes => Tonic + validation locale outbound
Les conversions request et décodeurs update introduits sous #[cfg(test)] en pre.004–008 deviennent ici des helpers runtime privés réellement consommés. Aucun type Tonic/protobuf n'est exposé dans l'API publique.
Le reconnect est volontairement absent de pre.009 : un server half-close est normal et terminal pour cette tranche ; un Status ou une erreur de protocole termine la session. from_slot, ReplayInfo, resubscribe, gaps/duplicates et changement de node restent pre.010. SubscribeDeshred, PublicNode et Config V3 restent hors scope.
Gate candidat : audit statique clean ; fixture locale couvre round-trip, mutation, Ping/Pong, server half-close, client half-close, shutdown hostile borné, Drop best-effort, update overflow, Status distant sûr, update malformed et rejet outbound oversized. Compilation/Clippy/tests opérateur requis avant fermeture.
27. pre.009-fix.001 — compaction de l’update transaction et hygiène du canari Send
Le gate opérateur de pre.009 valide intégralement le comportement bidi : fmt/audit/check passent ; Transport passe 379/379 unit, 48/48 public API, 42/42 release-completeness et 4/4 doctests ; le dependency canary Core passe 3/3 et cargo test --workspace est vert. Clippy termine avec succès mais signale deux warnings :
large_enum_variant YellowstoneSubscribeUpdate::Transaction
extra_unused_type_parameters assert_send<T: Send>() dans tests/public_api.rs
Le fix applique deux corrections sans allow :
YellowstoneSubscribeUpdate::Transactiontransporte désormaisBox<YellowstoneTransactionUpdate>. La queue ne réserve donc plus la taille de la variante transaction (~664 octets) pour chaque élément ; le wire et le DTO transaction eux-mêmes restent inchangés. La modification intervient avant fermeture de la candidatepre.009.- le canari
assert_send<T: Send>()matérialisePhantomData<T>afin que le paramètre générique soit effectivement utilisé tout en conservant exactement la même preuve compile-time.
Aucun changement n’est apporté aux neuf variantes wire, à la mutation request, à Ping/Pong, au half-close, au shutdown, à la backpressure, aux dépendances ou aux frontières de pre.010.
Gate fix requis : fmt/audit/check/Clippy sans warning + Transport 379/48/42/4 + dependency canary + workspace.