# Delta `0.2.4-pre.008` — `getInflationReward` complet + invariants positionnels ## Base requise Livraison précédente : ```text 0.2.4-pre.007 workspace.package.version = "0.2.4-pre.7" ``` Les validations locales fournies pour cette base sont propres : ```text cargo fmt --all -> terminé cargo check --workspace -> terminé sans warning cargo clippy --workspace --all-targets -> terminé sans warning cargo test -p ksp-onchain-transport-lib -> 231 unit tests OK 25 public API tests OK 20 release-completeness tests OK 1 smoke Devnet ignoré comme prévu 0 échec ``` ## Objectif Achever la surface Economics `0.2.4` avec le dernier wrapper prévu : ```text getInflationReward ``` La tranche doit conserver sans perte : ```text ordre exact des adresses d'entrée cardinalité exacte de la réponse null positionnels config epoch / commitment / minContextSlot commission nullable commissionBps présent / omis / null de compatibilité absence de limite métier d'adresses inventée par KSP erreurs RPC runtime ``` À l'issue de cette tranche, les `10/10` wrappers Blocks et `5/5` wrappers Economics de `V0_2_4` sont matérialisés. La compliance globale `52/52 + 14/14` reste volontairement réservée à `pre.009`. ## Réaudit primaire du contrat Agave stable Baseline stable conservée : ```text Agave v4.2.1 ``` Le serveur expose : ```text getInflationReward( address_strs: Vec, config: Option, ) -> Vec> ``` `RpcEpochConfig` contient : ```text epoch: Option commitment: Option minContextSlot: Option ``` Le runtime reconstruit son résultat en itérant sur la liste d'adresses d'origine. Il restitue donc une position par entrée : ```text reward trouvé -> Some(RpcInflationReward) reward absent -> None / JSON null ``` Cette propriété justifie le contrôle KSP explicite de cardinalité : une réponse dont la longueur diffère du nombre d'adresses demandées est un wire invalide pour le wrapper typed. ## Correction de contrat découverte pendant `pre.008` Le plan `011` n'explicitait pas encore la contrainte effective de commitment de `getInflationReward`. Agave construit un `RpcContextConfig` depuis `RpcEpochConfig` puis appelle : ```text getBlocksWithLimit(first_slot_in_epoch, 1, Some(context_config)) ``` Cette voie applique la contrainte runtime : ```text commitment >= confirmed ``` Conséquence KSP : ```text commitment = processed -> rejet déterministe avant I/O commitment = confirmed -> accepté commitment = finalized -> accepté commitment absent -> défaut runtime accepté ``` Le plan `011` passe donc de la version `4` à la version `5` avec : - la nouvelle contrainte locale `getInflationReward commitment >= confirmed`; - la matrice Economics corrigée; - le libellé de `pre.008` complété par le réaudit de commitment. Aucun autre changement de planning n'est effectué. ## SIMD-0291 — Commission Rate in Basis Points Le document SIMD courant reste au statut : ```text Review ``` La baseline Agave stable `v4.2.1` expose néanmoins déjà : ```text RpcInflationReward { epoch, effective_slot, amount, post_balance, commission: Option, commission_bps: Option, } ``` KSP conserve donc deux informations indépendantes : ```text commission -> Option commissionBps -> SolanaWireField ``` Aucune conversion `bps -> pourcentage` n'est réalisée. Aucun champ n'est dérivé depuis l'autre. Le wire KSP accepte et distingue : ```text commissionBps présent commissionBps omis commissionBps explicitement null pour compatibilité provider/wire ``` Même si Agave stable sérialise normalement l'absence via omission, conserver `null` séparément respecte la politique générale `SolanaWireField` et évite une normalisation destructive. ## Version Cargo Nouvelle prerelease technique : ```text 0.2.4-pre.7 -> 0.2.4-pre.8 ``` Aucune dépendance ni feature Cargo n'est ajoutée ou modifiée. ## Surface publique `getInflationReward` Nouvelle méthode : ```text HttpTransportPool::get_inflation_reward( role, &[Pubkey], Option<&SolanaInflationRewardConfig>, ) -> Result>> ``` Le premier paramètre JSON-RPC est toujours la liste d'adresses, y compris lorsqu'elle est vide : ```text [] d'adresses -> params: [[]] ``` La config optionnelle est ajoutée uniquement lorsqu'elle contient au moins un champ : ```text None / config vide -> [addresses] config non vide -> [addresses, config] ``` Exemple complet : ```json [ ["address-1", "address-2"], { "epoch": 912, "commitment": "finalized", "minContextSlot": 431000000 } ] ``` ## Ordre, doublons et cardinalité Le wrapper ne trie ni ne déduplique les adresses. Une requête conceptuelle : ```text [A, B, A] ``` reste exactement : ```text [A, B, A] ``` et la réponse reste positionnelle : ```text [Some(reward A), None, Some(reward A)] ``` Après décodage du tableau JSON, KSP vérifie : ```text result.len() == addresses.len() ``` Sinon : ```text ERROR_CODE_INVALID_RESPONSE expected_count = ... actual_count = ... ``` ## Absence de limite d'adresses inventée Aucune constante métier n'est ajoutée pour `getInflationReward`. En particulier, KSP ne réutilise pas artificiellement : ```text 256 # getSignatureStatuses 1000 # getSignaturesForAddress ``` ou toute autre limite d'un RPC voisin. Une canary HTTP construit une requête de : ```text 300 adresses ``` et vérifie qu'elle atteint réellement le serveur fixture puis que les `300` `null` sont restitués. La limite générale de taille d'une requête HTTP reste une contrainte de transport/provider, pas une cardinalité métier inventée par ce wrapper. ## Erreurs runtime préservées Deux erreurs spécifiques sont couvertes par fixtures : ```text -32016 MinContextSlotNotReached -32017 EpochRewardsPeriodActive ``` Elles restent : ```text ERROR_CODE_RPC_APPLICATION_ERROR ``` et ne sont pas converties en erreurs de décodage locales. Les autres erreurs runtime possibles liées à l'historique/epoch restent également transportées par le flux JSON-RPC central, notamment les familles BlockCleanedUp, BlockNotAvailable, SlotNotEpochBoundary et long-term storage lorsqu'elles surviennent réellement. ## Discipline `#[cfg(test)]` La politique introduite par `pre.002-fix.001` reste appliquée. Deviennent runtime uniquement parce qu'ils ont maintenant un consommateur réel : ```text SolanaInflationRewardConfig::is_empty SolanaInflationRewardConfig::to_json_value SolanaInflationReward::decode_wire WireInflationReward ``` Ils rejoignent les helpers Economics activés en `pre.007`. Aucun `#[allow(dead_code)]` n'est ajouté. ## Chemin d'exécution Le wrapper suit la frontière existante : ```text get_inflation_reward -> economics_descriptor("getInflationReward") -> HttpTransportPool::execute_standard_rpc -> decode_inflation_rewards ``` Le descriptor central reste : ```text V0_2_4 / Economics / Read / RetrySafe ``` Aucun chemin HTTP parallèle n'est créé. ## Fixtures Nouvelles fixtures HTTP : ```text get_inflation_reward.success.json get_inflation_reward.duplicates.json get_inflation_reward.single_null.json get_inflation_reward.empty.json get_inflation_reward.many_nulls.json get_inflation_reward.error_min_context.json get_inflation_reward.error_epoch_rewards_active.json ``` Elles couvrent : - config complète; - ordre positionnel; - doublons d'adresses; - `null` positionnels; - `commission` nullable; - `commissionBps` présent / omis / null; - tableau d'adresses vide; - 300 adresses sans limite métier KSP; - erreurs RPC runtime. ## Tests Neuf nouveaux tests unitaires couvrent : ```text config complète + positions + états commission/commissionBps ordre des doublons + null positionnel config absente/vide tout en conservant le paramètre addresses liste d'adresses vide 300 adresses sans limite locale 256 processed rejeté avant I/O mismatch de cardinalité rejeté MinContextSlotNotReached préservé EpochRewardsPeriodActive préservé ``` Canary public API : ```text public_v0_2_4_pre_008_inflation_reward_wrapper_is_available_from_crate_root ``` Canary release : ```text release_v0_2_4_pre_008_completes_all_five_economics_wrappers_exactly_and_retry_safe ``` La canary globale : ```text release_v0_2_4_descriptor_set_is_exact_and_remains_read_retry_safe_during_staged_wrappers ``` est renommée : ```text release_v0_2_4_descriptor_set_is_exact_and_remains_read_retry_safe_through_wrapper_completion ``` car `pre.008` achève désormais les `15/15` wrappers `V0_2_4`. Compteurs attendus après validation locale : ```text 240 unit tests 26 public API tests 21 release-completeness tests 1 smoke Devnet ignoré ``` ## Fichiers modifiés ```text Cargo.toml crates/ksp-onchain-transport-lib/src/rpc_economics.rs crates/ksp-onchain-transport-lib/unit_tests/rpc_economics.rs crates/ksp-onchain-transport-lib/tests/public_api.rs crates/ksp-onchain-transport-lib/tests/release_completeness.rs docs/plans/011-V0_2_4_HTTP_BLOCKS_ECONOMICS_PLAN.md ``` ## Fichiers ajoutés ```text crates/ksp-onchain-transport-lib/fixtures/http/get_inflation_reward.success.json crates/ksp-onchain-transport-lib/fixtures/http/get_inflation_reward.duplicates.json crates/ksp-onchain-transport-lib/fixtures/http/get_inflation_reward.single_null.json crates/ksp-onchain-transport-lib/fixtures/http/get_inflation_reward.empty.json crates/ksp-onchain-transport-lib/fixtures/http/get_inflation_reward.many_nulls.json crates/ksp-onchain-transport-lib/fixtures/http/get_inflation_reward.error_min_context.json crates/ksp-onchain-transport-lib/fixtures/http/get_inflation_reward.error_epoch_rewards_active.json deltas/0.2.4/pre.008.md ``` ## Non-objectifs Cette tranche ne réalise pas encore : - le réaudit SIMD final `0180/0298/0301/0307/0385/0490/0550/0553`; - le réaudit final de l'inventaire officiel HTTP; - la preuve globale `52/52 wrappers current`; - la preuve globale `14/14 historical Deprecated/runtime Removed`; - les smokes de clôture; - les graphes finaux de dépendances; - la documentation de clôture et le prompt `0.2.5`. Ces points restent réservés à `pre.009`. ## Validation attendue ```bash cargo fmt --all cargo check --workspace cargo clippy --workspace --all-targets cargo test -p ksp-onchain-transport-lib ``` Résultat attendu : ```text 0 warning introduit 240 unit tests OK 26 public API tests OK 21 release-completeness tests OK 1 smoke Devnet ignoré 0 échec ``` ## Commit attendu ```text v0.2.4-pre.008 ``` ## Suite `0.2.4-pre.009` reste la tranche de clôture technique/documentaire : ```text réaudit SIMD HTTP final réaudit inventaire officiel compliance 52/52 + 14/14 KSP-TRANSPORT-007 final smokes graphes documentation prompt 0.2.5 — Wallet foundation ```