Files
2026-08-22 19:16:41 +02:00

6.0 KiB

Delta 0.2.7-pre.005 — limits adversariales + control frames + shutdown borné

1. Base requise

0.2.7-pre.004-fix.001 appliqué
workspace.package.version = 0.2.7-pre.4.fix.1

Le checkpoint opérateur reçu avant cette tranche est vert : cargo fmt --all, audit Python, cargo check --workspace, cargo clippy --workspace --all-targets et cargo test --workspace. Les 261 tests unitaires Transport de pre.004-fix.001 passent également.

2. Signal technique

Cette prerelease modifie le runtime Rust, les tests et la documentation. Conformément aux règles KSP :

livraison                 = 0.2.7-pre.005
workspace.package.version = 0.2.7-pre.5
commit                    = v0.2.7-pre.005

Aucun tag prerelease.

3. Shutdown explicite WsSession::close()

Nouvelle surface publique :

WsSession::close().await

Le signal de shutdown est transporté par un canal watch distinct de la command queue. Une command queue saturée ne peut donc pas empêcher la demande de fermeture.

Lifecycle :

Active -> Closing -> Closed
remote Close propre -> Closed
I/O ou violation protocolaire -> Failed

close() :

  1. publie la demande de shutdown avec une deadline issue de close_timeout ;
  2. l'actor passe Closing ;
  3. toutes les requests JSON-RPC pending reçoivent ws_session_closed ;
  4. l'actor tente un Close WebSocket best-effort sous la deadline ;
  5. l'actor publie Closed ;
  6. le caller attend Closed sans pouvoir rester bloqué indéfiniment.

Le reconnect reste absent jusqu'à pre.007.

4. Control frames

Ping/Pong/Close sont maintenant testés explicitement.

Pour Ping, Tungstenite met automatiquement le Pong correspondant en file lors de la lecture ; KSP force le flush de cette réponse automatique. Aucun Pong duplicatif et aucun heartbeat applicatif périodique ne sont ajoutés.

Un Close distant propre est distingué d'une rupture I/O : il termine la session en Closed, alors qu'une rupture physique ou une violation de protocole termine en Failed.

5. Bornes frame/message/write

Les limites configurées depuis pre.002 et raccordées à Tungstenite depuis pre.004 sont désormais couvertes par des fixtures adversariales :

max_message_size
max_frame_size
max_write_buffer_size

Un payload JSON-RPC outbound dépassant max_message_size ou max_frame_size est rejeté avant écriture avec invalid_rpc_parameters, sans teardown d'une session saine.

Un frame/message inbound surdimensionné est rejeté par Tungstenite avant que KSP tente le parse JSON ; l'anomalie est classée protocolaire et la session devient Failed.

Aucune limite legacy Solana de type 1232 bytes n'est introduite.

6. Pending requests et cancellation

Le runtime pre.005 ajoute les preuves suivantes :

  • max_pending_requests rejette uniquement la request excédentaire avec ws_backpressure_overflow ;
  • une request pending silencieuse expire selon command_timeout, reçoit timeout et libère immédiatement sa capacité ;
  • une fermeture explicite annule toutes les pending requests avec ws_session_closed ;
  • un receiver caller abandonné est purgé du pending map au prochain cycle actor, et reste de toute façon borné par la deadline de request.

La cancellation de subscriptions et les races unsubscribe/reconnect restent dans pre.006/pre.007.

7. Socket I/O borné et shutdown prioritaire

Les writes JSON-RPC et le flush Pong surveillent le signal shutdown pendant leur attente. La fermeture peut donc préempter une opération socket qui serait autrement bloquante.

Un write JSON-RPC dépassant command_timeout provoque une erreur caller bornée et termine la session physique, car l'état de l'écriture devient impropre à une poursuite sûre.

8. Fixtures adversariales locales

Les tests Transport ajoutent notamment :

pending capacity = 1 avec deuxième request rejetée isolément
oversized outbound request rejetée avant write
oversized inbound frame/message rejeté avant JSON
pending request timeout + purge
Ping -> Pong + session toujours Active
remote Close -> Closed
close explicite + pending cancellation + peer hostile
8 cycles connect/close bornés

Toutes les fixtures restent locales et déterministes ; aucun réseau Solana réel n'est requis.

9. Logging / sécurité

Toutes les émissions passent exclusivement par ksp-logging-lib et réutilisent :

TRACING_TARGET = "ksp-onchain-transport-lib"

Les nouveaux diagnostics ne loggent que session ID, endpoint logique, méthode statique, compteurs et tailles numériques. Les URLs, credentials, query tokens et payloads JSON restent absents.

Les erreurs Tungstenite brutes ne sont pas projetées dans les erreurs KSP afin d'éviter une fuite de données provider.

10. Public API et documentation

Le canari public API vérifie désormais WsSession::close et les états Closing/Closed.

Synchronisés :

crates/ksp-onchain-transport-lib/README.md
crates/ksp-onchain-transport-lib/USAGE.md
docs/plans/014-V0_2_7_ONCHAIN_WEBSOCKET_PLAN.md
docs/validation/010-V0_2_7_ONCHAIN_WEBSOCKET.md

ROADMAP.md et CHANGELOG.md restent inchangés pendant la série prerelease.

11. Validation de préparation

Le sandbox de génération doit au minimum vérifier :

python3 scripts/audit_rust_workspace_rules.py
absence de tracing direct
présence du TRACING_TARGET existant
absence de question-mark operator dans le runtime modifié
overlay exact du delta

Cargo n'est pas disponible dans le sandbox de génération ; aucun résultat Cargo local n'est revendiqué.

12. Gates opérateur avant commit

cargo fmt --all
python3 scripts/audit_rust_workspace_rules.py
cargo check --workspace
cargo clippy --workspace --all-targets
cargo test -p ksp-onchain-transport-lib
cargo test --workspace

Si le checkpoint est vert :

commit = v0.2.7-pre.005

La tranche suivante est 0.2.7-pre.006 : registry subscriptions, IDs locaux stables, moteur generic subscribe/unsubscribe et channels typed bornés.