# Delta `0.2.3-pre.004` — lectures Transaction avec cardinalités et statuts positionnels ## Base requise Livraison précédente validée localement par l'opérateur : ```text 0.2.3-pre.003 workspace.package.version = "0.2.3-pre.3" ``` La validation opérateur du 2026-08-18 a confirmé : ```text cargo fmt --all OK cargo check --workspace OK cargo clippy --workspace --all-targets OK cargo test -p ksp-onchain-transport-lib OK ``` Résultats Transport de cette base : ```text 152 unit tests 15 public API tests 9 release completeness tests 0 warning signalé par check/clippy ``` Le plan canonique reste `docs/plans/010-V0_2_3_HTTP_TRANSACTIONS_PLAN.md` version 3. ## Objectif Implémenter les trois wrappers Transaction `Read / RetrySafe` prévus par la tranche `pre.004` : ```text getRecentPrioritizationFees getSignaturesForAddress getSignatureStatuses ``` Ils rejoignent les quatre reads de `pre.003`, portant la surface Transaction typée exécutée à : ```text 7 / 11 wrappers ``` Les quatre méthodes restantes restent volontairement différées : ```text getTransaction requestAirdrop sendTransaction simulateTransaction ``` ## Version Cargo Conformément à `VER-ID-009` : ```text 0.2.3-pre.3 -> 0.2.3-pre.4 ``` Aucune dépendance ni feature Cargo n'est ajoutée. ## `getRecentPrioritizationFees` Surface publique conceptuelle : ```text role + Option<&[Pubkey]> -> Vec ``` Le tableau d'adresses reste optionnel : - `None` omet entièrement le paramètre ; - `Some(slice)` sérialise exactement un tableau d'adresses ; - l'ordre des adresses caller est conservé ; - les résultats restent dans l'ordre renvoyé par le provider. La cardinalité runtime documentée est appliquée avant I/O : ```text 0..=128 accepté 129+ ERROR_CODE_INVALID_RPC_PARAMETERS ``` Le test couvre explicitement la borne `128` puis le rejet de `129`. Aucune règle locale n'est créée à partir de la profondeur actuelle de cache des prioritization fees : la valeur d'environ 150 blocs est une caractéristique runtime du noeud et non une cardinalité client. ## `getSignaturesForAddress` Surface publique conceptuelle : ```text role + Pubkey + Option -> Vec ``` La config préparée en `pre.002` devient production-live pour cette méthode : ```text before until limit commitment minContextSlot ``` Une config absente ou entièrement vide est omise. La limite est validée avant I/O exactement selon le runtime audité : ```text 1..=1000 accepté quand limit est fourni 0 rejeté 1001+ rejeté ``` La fixture de succès utilise explicitement `limit = 1000`, puis les tests rejettent `0` et `1001`. Le résultat conserve notamment : ```text signature slot err nullable memo nullable blockTime nullable confirmationStatus nullable transactionIndex optionnel ``` L'ordre `newest -> oldest` du provider n'est jamais retrié côté KSP. Les signatures restent des chaînes wire opaques dans cette release. Une fixture JSON-RPC d'erreur vérifie qu'une indisponibilité de transaction history reste une `RPC_APPLICATION_ERROR`, sans être transformée en retry Transport. ## `getSignatureStatuses` Surface publique conceptuelle : ```text role + &[String] + Option -> SolanaRpcResponse>> ``` La config `searchTransactionHistory` préparée en `pre.002` devient production-live. Une config vide est omise. Le tableau d'entrée suit exactement la borne Agave auditée : ```text 0..=256 accepté 257+ ERROR_CODE_INVALID_RPC_PARAMETERS ``` Le tableau vide reste volontairement accepté, conformément au runtime `v4.2.1` audité en `pre.001`. La borne `256` est exercée par une fixture contenant 256 positions `null` et `257` est rejeté avant I/O. Le résultat conserve strictement la correspondance positionnelle : ```text entrée[i] <-> value[i] null -> None objet -> Some(SolanaSignatureStatus) ``` KSP vérifie maintenant que le provider retourne exactement autant de positions que de signatures demandées. Une longueur différente produit `ERROR_CODE_INVALID_RESPONSE`, car continuer masquerait la correspondance signature/statut. Pour un statut présent, les champs suivants restent préservés : ```text slot confirmations nullable status legacy lossless JSON err nullable confirmationStatus nullable ``` La forme `status` demeure un champ legacy du wire courant ; elle n'est pas confondue avec les anciennes méthodes RPC Deprecated. ## Helpers activés en production Seuls les helpers nécessaires à cette tranche quittent `#[cfg(test)]` : ```text SolanaSignaturesForAddressConfig::{is_empty,to_json_value} SolanaSignatureStatusesConfig::{is_empty,to_json_value} SolanaPrioritizationFee::decode_wire SolanaSignatureInfo::decode_wire SolanaSignatureStatus::decode_wire decode_confirmation_status WirePrioritizationFee WireSignatureInfo WireSignatureStatus ``` Les helpers de `getTransaction`, `requestAirdrop`, `sendTransaction` et `simulateTransaction` restent staged/test-only jusqu'à leur tranche propriétaire. Aucun `#[allow(dead_code)]` n'est introduit. ## Fixtures HTTP déterministes ajoutées ```text crates/ksp-onchain-transport-lib/fixtures/http/get_recent_prioritization_fees.success.json crates/ksp-onchain-transport-lib/fixtures/http/get_signatures_for_address.success.json crates/ksp-onchain-transport-lib/fixtures/http/get_signatures_for_address.error.json crates/ksp-onchain-transport-lib/fixtures/http/get_signature_statuses.success.json crates/ksp-onchain-transport-lib/fixtures/http/get_signature_statuses.empty.json crates/ksp-onchain-transport-lib/fixtures/http/get_signature_statuses.max_256.json crates/ksp-onchain-transport-lib/fixtures/http/get_signature_statuses.count_mismatch.json ``` Les tests HTTP utilisent uniquement un serveur loopback local. ## Couverture de tests ajoutée Neuf tests unitaires HTTP supplémentaires couvrent : - paramètres exacts de `getRecentPrioritizationFees` et ordre serveur ; - omission du paramètre optionnel ; - acceptation de 128 adresses et rejet local de 129 ; - pagination/config complète de `getSignaturesForAddress` avec `limit = 1000` ; - rejet local de `limit = 0` et `limit = 1001` ; - propagation d'une erreur JSON-RPC applicative ; - `getSignatureStatuses` avec `searchTransactionHistory = true` et positions `null` ; - tableau vide + config vide omise ; - borne 256 acceptée, 257 rejetée et longueur de réponse incohérente rejetée. Un test public compile les trois nouveaux wrappers depuis la crate root. Une nouvelle canarie release fige le sous-ensemble Read exécuté cumulé de `pre.003 + pre.004` : ```text getFeeForMessage getLatestBlockhash getRecentPrioritizationFees getSignaturesForAddress getSignatureStatuses getTransactionCount isBlockhashValid ``` Chaque descriptor reste : ```text Transactions / V0_2_3 / Read / RetrySafe ``` La canarie confirme aussi que les quatre méthodes différées restent enregistrées dans `V0_2_3` sans les compter comme surface typée achevée. Après application, la cible Transport attendue devient : ```text 161 unit tests 16 public API tests 10 release completeness tests ``` ## Fichiers ajoutés ```text crates/ksp-onchain-transport-lib/fixtures/http/get_recent_prioritization_fees.success.json crates/ksp-onchain-transport-lib/fixtures/http/get_signatures_for_address.success.json crates/ksp-onchain-transport-lib/fixtures/http/get_signatures_for_address.error.json crates/ksp-onchain-transport-lib/fixtures/http/get_signature_statuses.success.json crates/ksp-onchain-transport-lib/fixtures/http/get_signature_statuses.empty.json crates/ksp-onchain-transport-lib/fixtures/http/get_signature_statuses.max_256.json crates/ksp-onchain-transport-lib/fixtures/http/get_signature_statuses.count_mismatch.json deltas/0.2.3/pre.004.md ``` ## Fichiers modifiés ```text Cargo.toml crates/ksp-onchain-transport-lib/src/lib.rs crates/ksp-onchain-transport-lib/src/rpc_transactions.rs crates/ksp-onchain-transport-lib/unit_tests/rpc_transactions.rs crates/ksp-onchain-transport-lib/tests/public_api.rs crates/ksp-onchain-transport-lib/tests/release_completeness.rs ``` Restent inchangés dans cette tranche : ```text CHANGELOG.md ROADMAP.md docs/plans/010-V0_2_3_HTTP_TRANSACTIONS_PLAN.md crates/ksp-onchain-transport-lib/Cargo.toml crates/ksp-onchain-transport-lib/src/executor.rs crates/ksp-onchain-transport-lib/src/resilience.rs crates/ksp-onchain-transport-lib/src/rpc_method.rs ``` ## Contrôles statiques effectués dans l'environnement d'échange - les sept nouvelles fixtures sont du JSON valide ; - aucune dépendance n'est ajoutée ; - aucun `reqwest`, `tracing`, retry local ou client parallèle n'est introduit par le diff ; - aucun `#[allow(dead_code)]` n'est introduit ; - les helpers des tranches futures restent `#[cfg(test)]` ; - aucune ligne Rust modifiée ne dépasse 160 colonnes ; - `CHANGELOG.md`, `ROADMAP.md`, le plan `010`, `executor.rs`, `resilience.rs` et `rpc_method.rs` restent identiques à `pre.003`. `cargo`, `rustc` et `rustfmt` ne sont pas installés dans l'environnement d'échange. Aucune validation Cargo de `pre.004` n'est donc déclarée réussie ici. ## Validation opérateur requise ```bash cargo fmt --all cargo check --workspace cargo clippy --workspace --all-targets cargo test -p ksp-onchain-transport-lib ``` La validation doit notamment confirmer : ```text 0 warning check/clippy 161 unit tests 16 public API tests 10 release completeness tests ``` Le smoke Devnet reste opt-in et n'est pas requis pour cette tranche locale déterministe. ## Hors scope maintenu `pre.004` ne traite pas : - `getTransaction` moderne/legacy ; - `requestAirdrop` ; - `sendTransaction` ; - la preuve end-to-end no-resend des writes ; - `simulateTransaction` ; - les 15 méthodes `0.2.4` Blocks/Economics ; - un nouveau smoke cross-crates. La prochaine tranche reste `pre.005` : `getTransaction` moderne, compatibilité legacy et wire transaction/meta/version.