# Delta `0.2.3-pre.002` — primitives Transaction et wire partagé ## Base requise Livraison précédente : ```text 0.2.3-pre.001 workspace.package.version = "0.2.3-pre.1" ``` Le plan canonique de départ est `docs/plans/010-V0_2_3_HTTP_TRANSACTIONS_PLAN.md` version 2, avec l'alignement Markdown corrigé par l'opérateur avant cette tranche. ## Objectif Installer les primitives, configurations et résultats partagés nécessaires aux 11 wrappers Transactions `0.2.3`, ainsi que des fixtures wire locales déterministes, sans encore implémenter les quatre premiers wrappers Read prévus pour `pre.003` et sans déclarer la couverture typed `0.2.3` complète. Cette tranche doit préserver les unions/nullable/omissions du wire Transaction tout en restant une couche Transport : aucun décodage Program, aucune construction/signature de transaction et aucun client RPC Solana parallèle ne sont introduits. ## Version Cargo Conformément à `VER-ID-009`, la nouvelle prerelease synchronise le signal technique : ```text 0.2.3-pre.1 -> 0.2.3-pre.2 ``` Aucune dépendance ou feature Cargo n'est ajoutée. ## Implémentation ### Encodings et champs wire Le nouveau module `rpc_transactions` ajoute : ```text SolanaTransactionBinaryEncoding SolanaTransactionEncoding SolanaWireField ``` `SolanaTransactionBinaryEncoding` borne les entrées sérialisées `sendTransaction`/`simulateTransaction` à `base58 | base64` sans décoder les bytes. `SolanaTransactionEncoding` conserve la surface plus large de `getTransaction` : `binary` legacy, `base58`, `base64`, `json` et `jsonParsed`. `SolanaWireField` matérialise explicitement les trois états qui comptent sur les réponses Transaction évolutives : ```text Omitted Null Value(T) ``` Cette primitive évite de fusionner un champ absent avec un champ explicitement `null`, notamment pour `getTransaction` et `simulateTransaction`. ### Configurations partagées Les configurations suivantes sont ajoutées : ```text SolanaGetTransactionConfig SolanaSignaturesForAddressConfig SolanaSignatureStatusesConfig SolanaRequestAirdropConfig SolanaSendTransactionConfig SolanaSimulationAccountsConfig SolanaSimulateTransactionConfig ``` Elles sérialisent uniquement les options explicitement fournies. `SolanaSendTransactionConfig::max_retries` reste nommé et documenté comme une limite de retransmission **côté noeud RPC** et ne modifie jamais la retry policy HTTP KSP. Les validations propres aux wrappers restent volontairement dans leurs tranches d'exécution : limites `128 / 1000 / 256`, encodings Account interdits pour le retour de simulation et incompatibilité `sigVerify + replaceRecentBlockhash` ne sont pas transformés ici en une seconde policy parallèle. ### Résultats et DTOs Transaction Les résultats communs suivants sont ajoutés : ```text SolanaLatestBlockhash SolanaPrioritizationFee SolanaTransactionConfirmationStatus SolanaSignatureInfo SolanaSignatureStatus SolanaEncodedTransaction SolanaTransactionVersion SolanaConfirmedTransaction SolanaSimulateTransactionResult ``` `SolanaEncodedTransaction` conserve séparément : ```text chaîne binaire legacy [data, "base58" | "base64"] objet JSON / jsonParsed ``` Aucun `base64`, `bs58` ou `wincode` n'est donc requis. Les objets Transaction/message riches restent lossless via `serde_json::Value` aux frontières où Transport ne possède pas de modèle métier. `SolanaConfirmedTransaction` conserve `meta`, `version` et `transactionIndex` avec la sémantique `Omitted | Null | Value`. Pendant l'implémentation de cette tranche, le recoupement direct avec Agave `v4.2.1` a confirmé que `EncodedConfirmedTransactionWithStatusMeta` expose également `transactionIndex: Option` au top-level de `getTransaction`. Le plan `010` passe donc en version 3 pour enregistrer cette précision wire additive ; il ne s'agit pas d'un changement de périmètre. `SolanaSimulateTransactionResult` conserve les champs Agave courants utiles, y compris les comptes positionnels nullable, unités consommées, loaded account data size, return data, inner instructions, replacement blockhash, fee, balances, token balances et loaded addresses. Les sous-structures Program/transaction riches restent volontairement opaques lorsqu'un modèle Transport étroit n'apporte pas de valeur. ### Validation de wire locale Les décodeurs partagés : - utilisent le domaine d'erreur Transport existant pour les shapes invalides ; - rejettent un `getLatestBlockhash.blockhash` vide sans tenter de le décoder ; - rejettent les labels de confirmation inconnus ; - rejettent les tuples transaction binaires mal formés ou utilisant un encoding non binaire ; - bornent le champ `version` de `getTransaction` à `legacy | u8` conformément au wire actuel ; - préservent les `null` positionnels des comptes de simulation. Ils ne désérialisent ni message ni transaction Solana. ## Fixtures déterministes ajoutées ```text crates/ksp-onchain-transport-lib/fixtures/http/latest_blockhash.v4_2_1.json crates/ksp-onchain-transport-lib/fixtures/http/prioritization_fee.v4_2_1.json crates/ksp-onchain-transport-lib/fixtures/http/signature_info.v4_2_1.json crates/ksp-onchain-transport-lib/fixtures/http/signature_status.variants.json crates/ksp-onchain-transport-lib/fixtures/http/encoded_transaction.variants.json crates/ksp-onchain-transport-lib/fixtures/http/confirmed_transaction.variants.json crates/ksp-onchain-transport-lib/fixtures/http/simulate_transaction_result.v4_2_1.json ``` Elles couvrent notamment : - latest blockhash ; - ordre de samples de prioritization fees ; - `transactionIndex` présent et absent sur les signatures ; - `null` positionnel pour les statuses ; - status legacy encore présent ; - transaction legacy, tuple base64 et JSON ; - `meta/version/transactionIndex` présents, `null` ou omis ; - résultat de simulation riche avec compte positionnel `null` et champs optionnels actuels. ## Tests ajoutés `unit_tests/rpc_transactions.rs` ajoute **18 tests déterministes** pour les enums/configs/décodeurs/fixtures de cette tranche. Les tests de surface ajoutent aussi : - un test public de construction/réexport des primitives Transaction depuis la racine de crate ; - une canarie de registre qui confirme l'ensemble exact des 11 descriptors `0.2.3` et leur répartition `8 Read / 2 WriteSubmission / 1 Simulation` sans prétendre que les 11 wrappers typed existent déjà. La canarie typed-complete `0.2.3 exact == 11` reste donc volontairement fermée jusqu'aux tranches de wrappers. ## Fichiers ajoutés ```text crates/ksp-onchain-transport-lib/src/rpc_transactions.rs crates/ksp-onchain-transport-lib/unit_tests/rpc_transactions.rs crates/ksp-onchain-transport-lib/fixtures/http/latest_blockhash.v4_2_1.json crates/ksp-onchain-transport-lib/fixtures/http/prioritization_fee.v4_2_1.json crates/ksp-onchain-transport-lib/fixtures/http/signature_info.v4_2_1.json crates/ksp-onchain-transport-lib/fixtures/http/signature_status.variants.json crates/ksp-onchain-transport-lib/fixtures/http/encoded_transaction.variants.json crates/ksp-onchain-transport-lib/fixtures/http/confirmed_transaction.variants.json crates/ksp-onchain-transport-lib/fixtures/http/simulate_transaction_result.v4_2_1.json deltas/0.2.3/pre.002.md ``` ## Fichiers modifiés ```text Cargo.toml crates/ksp-onchain-transport-lib/src/lib.rs crates/ksp-onchain-transport-lib/tests/public_api.rs crates/ksp-onchain-transport-lib/tests/release_completeness.rs docs/plans/010-V0_2_3_HTTP_TRANSACTIONS_PLAN.md ``` ## Fichiers supprimés Aucun. ## Fichiers volontairement inchangés ```text CHANGELOG.md ROADMAP.md crates/ksp-onchain-transport-lib/Cargo.toml crates/ksp-onchain-transport-lib/README.md crates/ksp-onchain-transport-lib/USAGE.md crates/ksp-onchain-transport-lib/src/executor.rs crates/ksp-onchain-transport-lib/src/rpc_method.rs crates/ksp-config-lib/** config/** ``` Aucun ancien delta n'est réécrit. Aucun wrapper `0.2.4` n'est avancé. ## Validations exécutées - reconstruction de la base `0.2.3-pre.001` puis remplacement du plan `010` par la version 2 corrigée fournie par l'opérateur ; - contrôle différentiel de la tranche contre cette base corrigée ; - recoupement ciblé des unions/configs/résultats avec les sources primaires Agave `v4.2.1` déjà normatives pour le plan ; - confirmation additive de `getTransaction.transactionIndex: Option` dans `EncodedConfirmedTransactionWithStatusMeta` ; - parse JSON local des sept nouvelles fixtures ; - contrôle statique des réexports crate-root des nouveaux types publics ; - contrôle statique de l'absence de nouveau client HTTP, de `reqwest` direct dans le module Transaction, de boucle de retry locale et de wrapper Transaction exécuté prématurément ; - contrôle statique de l'absence de nouvelle dépendance/feature Cargo ; - contrôle statique de l'absence de `unwrap`, `expect`, `panic!` et `?` dans la nouvelle source de production ; - contrôle statique des lignes Rust modifiées à `<= 160` colonnes ; - contrôle que `CHANGELOG.md` reste inchangé. ## Validations non exécutées Le sandbox ne fournit pas `cargo` ni `rustfmt`. Les commandes suivantes ne sont donc pas déclarées comme réussies et doivent être exécutées sur le checkout de développement avant commit : ```bash cargo fmt --all cargo check --workspace cargo clippy --workspace --all-targets cargo test -p ksp-onchain-transport-lib ``` Aucun `cargo tree` supplémentaire n'est requis par cette tranche puisqu'aucune dépendance ni feature n'a changé. Les vues de dépendances du prompt restent obligatoires à la clôture de `0.2.3`. Le commit attendu après application et validations suit `VER-GIT-001` : ```text v0.2.3-pre.002 ``` ## Décisions prises - conserver les payloads message/transaction sérialisés comme chaînes opaques tant qu'aucun invariant KSP n'exige leur décodage ; - distinguer l'encoding binaire d'entrée de la surface d'encoding plus large de `getTransaction` ; - représenter explicitement `absent / null / présent` lorsque le wire courant le nécessite ; - conserver `serde_json::Value` seulement aux frontières Transaction/Program riches et évolutives, plutôt que dupliquer tout `solana-transaction-status-client-types` ; - réutiliser `SolanaContextConfig`, `SolanaAccountEncoding`, `SolanaAccount` et les erreurs Transport existantes ; - ne pas ajouter les validations de wrapper avant leur tranche propriétaire ; - ajouter `getTransaction.transactionIndex` au plan et au DTO après confirmation Agave `v4.2.1`. ## Questions ouvertes Aucune question bloquante pour `pre.003`. Le formatage canonique final doit être produit par `cargo fmt --all`/`rustfmt` lors de l'application locale, puisque ces binaires ne sont pas disponibles dans le sandbox d'échange. ## Suite `0.2.3-pre.003` : implémenter `getFeeForMessage`, `getLatestBlockhash`, `getTransactionCount` et `isBlockhashValid` via le chemin `descriptor -> execute_standard_rpc`, avec requêtes exactes, résultats contextuels/nullables, erreurs RPC et fixtures HTTP locales.