diff --git a/Cargo.toml b/Cargo.toml index efb7e41..ae7d527 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,12 +1,12 @@ # file: Cargo.toml -# version: 132 +# version: 133 [workspace] resolver = "3" members = ["crates/ksp-app-config-desk", "crates/ksp-config-lib", "crates/ksp-core-lib", "crates/ksp-logging-lib", "crates/ksp-onchain-transport-lib"] [workspace.package] -version = "0.2.4-pre.2" +version = "0.2.4-pre.2.fix.1" edition = "2024" license = "MIT" repository = "https://git.sasedev.com/Sasedev/khadhroony-solana-project" diff --git a/crates/ksp-onchain-transport-lib/src/rpc_blocks.rs b/crates/ksp-onchain-transport-lib/src/rpc_blocks.rs index d1b1217..45c5140 100644 --- a/crates/ksp-onchain-transport-lib/src/rpc_blocks.rs +++ b/crates/ksp-onchain-transport-lib/src/rpc_blocks.rs @@ -1,5 +1,5 @@ // file: crates/ksp-onchain-transport-lib/src/rpc_blocks.rs -// version: 1 +// version: 2 /// Transaction detail level accepted by modern `getBlock` requests. #[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)] @@ -82,6 +82,7 @@ impl SolanaGetBlockConfig { } /// Returns whether this config would serialize to an empty object. + #[cfg(test)] pub(crate) const fn is_empty(&self) -> bool { return self.commitment.is_none() && self.encoding.is_none() @@ -92,6 +93,7 @@ impl SolanaGetBlockConfig { /// Serializes this config to the exact Solana JSON-RPC object. #[must_use] + #[cfg(test)] pub(crate) fn to_json_value(self) -> serde_json::Value { let mut object = serde_json::Map::new(); if let std::option::Option::Some(commitment) = self.commitment { @@ -141,6 +143,7 @@ impl SolanaBlockProductionRange { /// Serializes this range to the exact Solana JSON-RPC object. #[must_use] + #[cfg(test)] pub(crate) fn to_json_value(self) -> serde_json::Value { let mut object = serde_json::Map::new(); object.insert("firstSlot".to_owned(), serde_json::Value::Number(self.first_slot.into())); @@ -189,12 +192,14 @@ impl SolanaBlockProductionConfig { } /// Returns whether this config would serialize to an empty object. + #[cfg(test)] pub(crate) const fn is_empty(&self) -> bool { return self.commitment.is_none() && self.identity.is_none() && self.range.is_none(); } /// Serializes this config to the exact Solana JSON-RPC object. #[must_use] + #[cfg(test)] pub(crate) fn to_json_value(&self) -> serde_json::Value { let mut object = serde_json::Map::new(); if let std::option::Option::Some(commitment) = self.commitment { @@ -231,6 +236,7 @@ impl SolanaBlockCommitment { } /// Decodes a block-commitment result from its Solana JSON wire shape. + #[cfg(test)] pub(crate) fn decode_wire(method: &str, value: serde_json::Value) -> ksp_core_lib::Result { let decoded = crate::decode_wire_json::(method, value); return match decoded { @@ -282,6 +288,7 @@ impl SolanaBlockProduction { } /// Decodes a block-production result from its Solana JSON wire shape. + #[cfg(test)] pub(crate) fn decode_wire(method: &str, value: serde_json::Value) -> ksp_core_lib::Result { let decoded = crate::decode_wire_json::(method, value); let wire = match decoded { @@ -352,6 +359,7 @@ impl SolanaBlockReward { return &self.commission_bps; } + #[cfg(test)] fn decode_wire(method: &str, value: serde_json::Value) -> ksp_core_lib::Result { let decoded = crate::decode_wire_json::(method, value); let wire = match decoded { @@ -400,6 +408,7 @@ impl SolanaBlockTransaction { return &self.version; } + #[cfg(test)] fn decode_wire(method: &str, value: serde_json::Value) -> ksp_core_lib::Result { let decoded = crate::decode_wire_json::(method, value); let wire = match decoded { @@ -489,6 +498,7 @@ impl SolanaConfirmedBlock { } /// Decodes a confirmed block from its Solana JSON wire shape. + #[cfg(test)] pub(crate) fn decode_wire(method: &str, value: serde_json::Value) -> ksp_core_lib::Result { let decoded = crate::decode_wire_json::(method, value); let wire = match decoded { @@ -561,6 +571,7 @@ impl SolanaPerformanceSample { } /// Decodes one performance sample from its Solana JSON wire shape. + #[cfg(test)] pub(crate) fn decode_wire(method: &str, value: serde_json::Value) -> ksp_core_lib::Result { let decoded = crate::decode_wire_json::(method, value); return match decoded { @@ -576,6 +587,7 @@ impl SolanaPerformanceSample { } } +#[cfg(test)] fn decode_block_transaction_version( method: &str, field: crate::SolanaWireField, @@ -593,6 +605,7 @@ fn decode_block_transaction_version( }; } +#[cfg(test)] fn decode_block_transactions( method: &str, field: crate::SolanaWireField>, @@ -613,6 +626,7 @@ fn decode_block_transactions( return std::result::Result::Ok(crate::SolanaWireField::Value(transactions)); } +#[cfg(test)] fn decode_block_rewards( method: &str, field: crate::SolanaWireField>, @@ -633,6 +647,7 @@ fn decode_block_rewards( return std::result::Result::Ok(crate::SolanaWireField::Value(rewards)); } +#[cfg(test)] #[derive(serde::Deserialize)] #[serde(rename_all = "camelCase")] struct WireBlockCommitment { @@ -640,6 +655,7 @@ struct WireBlockCommitment { total_stake: u64, } +#[cfg(test)] #[derive(serde::Deserialize)] #[serde(rename_all = "camelCase")] struct WireBlockProductionRange { @@ -647,6 +663,7 @@ struct WireBlockProductionRange { last_slot: u64, } +#[cfg(test)] #[derive(serde::Deserialize)] #[serde(rename_all = "camelCase")] struct WireBlockProduction { @@ -654,6 +671,7 @@ struct WireBlockProduction { range: WireBlockProductionRange, } +#[cfg(test)] #[derive(serde::Deserialize)] #[serde(rename_all = "camelCase")] struct WireBlockReward { @@ -668,6 +686,7 @@ struct WireBlockReward { commission_bps: crate::SolanaWireField, } +#[cfg(test)] #[derive(serde::Deserialize)] #[serde(rename_all = "camelCase")] struct WireBlockTransaction { @@ -678,6 +697,7 @@ struct WireBlockTransaction { version: crate::SolanaWireField, } +#[cfg(test)] #[derive(serde::Deserialize)] #[serde(rename_all = "camelCase")] struct WireConfirmedBlock { @@ -696,6 +716,7 @@ struct WireConfirmedBlock { block_height: std::option::Option, } +#[cfg(test)] #[derive(serde::Deserialize)] #[serde(rename_all = "camelCase")] struct WirePerformanceSample { diff --git a/crates/ksp-onchain-transport-lib/src/rpc_economics.rs b/crates/ksp-onchain-transport-lib/src/rpc_economics.rs index e30b4c7..15c1642 100644 --- a/crates/ksp-onchain-transport-lib/src/rpc_economics.rs +++ b/crates/ksp-onchain-transport-lib/src/rpc_economics.rs @@ -1,5 +1,5 @@ // file: crates/ksp-onchain-transport-lib/src/rpc_economics.rs -// version: 1 +// version: 2 /// Inflation-governor values returned by `getInflationGovernor`. #[derive(Clone, Copy, Debug, PartialEq)] @@ -43,6 +43,7 @@ impl SolanaInflationGovernor { } /// Decodes an inflation-governor result from its Solana JSON wire shape. + #[cfg(test)] pub(crate) fn decode_wire(method: &str, value: serde_json::Value) -> ksp_core_lib::Result { let decoded = crate::decode_wire_json::(method, value); return match decoded { @@ -93,6 +94,7 @@ impl SolanaInflationRate { } /// Decodes an inflation-rate result from its Solana JSON wire shape. + #[cfg(test)] pub(crate) fn decode_wire(method: &str, value: serde_json::Value) -> ksp_core_lib::Result { let decoded = crate::decode_wire_json::(method, value); return match decoded { @@ -142,12 +144,14 @@ impl SolanaInflationRewardConfig { } /// Returns whether this config would serialize to an empty object. + #[cfg(test)] pub(crate) const fn is_empty(&self) -> bool { return self.epoch.is_none() && self.commitment.is_none() && self.min_context_slot.is_none(); } /// Serializes this config to the exact Solana JSON-RPC object. #[must_use] + #[cfg(test)] pub(crate) fn to_json_value(self) -> serde_json::Value { let mut object = serde_json::Map::new(); if let std::option::Option::Some(epoch) = self.epoch { @@ -212,6 +216,7 @@ impl SolanaInflationReward { } /// Decodes one non-null inflation reward from its Solana JSON wire shape. + #[cfg(test)] pub(crate) fn decode_wire(method: &str, value: serde_json::Value) -> ksp_core_lib::Result { let decoded = crate::decode_wire_json::(method, value); return match decoded { @@ -255,12 +260,14 @@ impl SolanaSupplyConfig { } /// Returns whether this config would serialize to an empty object. + #[cfg(test)] pub(crate) const fn is_empty(&self) -> bool { return self.commitment.is_none() && self.exclude_non_circulating_accounts_list.is_none(); } /// Serializes this config to the exact Solana JSON-RPC object. #[must_use] + #[cfg(test)] pub(crate) fn to_json_value(self) -> serde_json::Value { let mut object = serde_json::Map::new(); if let std::option::Option::Some(commitment) = self.commitment { @@ -308,6 +315,7 @@ impl SolanaSupply { } /// Decodes a supply result from its Solana JSON wire shape. + #[cfg(test)] pub(crate) fn decode_wire(method: &str, value: serde_json::Value) -> ksp_core_lib::Result { let decoded = crate::decode_wire_json::(method, value); let wire = match decoded { @@ -331,6 +339,7 @@ impl SolanaSupply { } } +#[cfg(test)] #[derive(serde::Deserialize)] #[serde(rename_all = "camelCase")] struct WireInflationGovernor { @@ -341,6 +350,7 @@ struct WireInflationGovernor { foundation_term: f64, } +#[cfg(test)] #[derive(serde::Deserialize)] #[serde(rename_all = "camelCase")] struct WireInflationRate { @@ -350,6 +360,7 @@ struct WireInflationRate { epoch: u64, } +#[cfg(test)] #[derive(serde::Deserialize)] #[serde(rename_all = "camelCase")] struct WireInflationReward { @@ -363,6 +374,7 @@ struct WireInflationReward { commission_bps: crate::SolanaWireField, } +#[cfg(test)] #[derive(serde::Deserialize)] #[serde(rename_all = "camelCase")] struct WireSupply { diff --git a/deltas/0.2.4/pre.002-fix.001.md b/deltas/0.2.4/pre.002-fix.001.md new file mode 100644 index 0000000..50c9286 --- /dev/null +++ b/deltas/0.2.4/pre.002-fix.001.md @@ -0,0 +1,159 @@ + + + +# Delta `0.2.4-pre.002-fix.001` — suppression du code interne prématurément actif + +## Base requise + +Livraison précédente : + +```text +0.2.4-pre.002 +workspace.package.version = "0.2.4-pre.2" +``` + +Ce fix corrige uniquement les warnings `dead_code` introduits par `pre.002` dans les nouveaux modules Blocks/Economics. Il ne redéfinit pas le périmètre fonctionnel de la prerelease et ne modifie ni les DTOs publics, ni les fixtures, ni les tests, ni le registre RPC. + +## Problème observé + +Les validations locales de `pre.002` ont montré que la tranche est fonctionnellement verte : + +```text +cargo fmt --all -> terminé +cargo check --workspace -> terminé avec 29 warnings dead_code +cargo clippy --workspace --all-targets -> terminé avec les mêmes 29 warnings dead_code +cargo test -p ksp-onchain-transport-lib -> 196 unit tests OK + 20 public API tests OK + 15 release-completeness tests OK + 1 smoke Devnet ignoré comme prévu + 0 échec +``` + +Les warnings proviennent exclusivement de helpers internes d'encodage/décodage et de structs `Wire*` préparés en `pre.002` pour les futurs wrappers, alors qu'aucun wrapper `V0_2_4` ne les consomme encore dans une compilation normale de la bibliothèque. + +Le choix `#[allow(dead_code)]` est rejeté : le lint est correct et signale du code de production activé trop tôt. + +## Correction + +Les 17 contrats publics ajoutés par `pre.002` restent compilés et exportés normalement. + +Seuls les éléments internes qui n'ont encore aucun consommateur runtime sont placés sous `#[cfg(test)]` : + +- helpers `is_empty` des configs Blocks/Economics ; +- helpers `to_json_value` des configs/ranges Blocks/Economics ; +- décodeurs internes `decode_wire` des résultats Blocks/Economics ; +- helpers privés de décodage des transactions/rewards de bloc ; +- structs privées `WireBlock*`, `WirePerformanceSample` et `WireInflation*`/`WireSupply`. + +Ils restent donc compilés par les unit tests de `pre.002`, qui continuent à valider les formes wire et les fixtures déterministes, mais ils ne participent plus au build normal de la crate tant qu'un wrapper runtime ne les utilise pas. + +Cette approche garde le découpage des prereleases strict : + +```text +pre.002 -> contrats publics + fixtures + validation test-only des helpers wire +pre.003+ -> activation progressive des helpers internes au moment où leur wrapper runtime existe +``` + +À partir de `pre.003`, `SolanaBlockCommitment::decode_wire` sera sorti de `#[cfg(test)]` avec l'implémentation de `getBlockCommitment`. Les autres encodeurs/décodeurs seront activés uniquement dans la prerelease qui introduit leur consommateur. + +Aucun `#[allow(dead_code)]` n'est ajouté. + +## Version Cargo + +Ce correctif modifie des sources Rust participant au build. Conformément à `VER-ID-007` et `VER-ID-010` : + +```text +0.2.4-pre.2 -> 0.2.4-pre.2.fix.1 +``` + +Aucune dépendance ni feature Cargo n'est modifiée. + +## Fichiers modifiés + +```text +Cargo.toml +crates/ksp-onchain-transport-lib/src/rpc_blocks.rs +crates/ksp-onchain-transport-lib/src/rpc_economics.rs +``` + +## Fichiers ajoutés + +```text +deltas/0.2.4/pre.002-fix.001.md +``` + +## Fichiers supprimés + +Aucun. + +## Fichiers volontairement inchangés + +```text +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_blocks.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 +crates/ksp-onchain-transport-lib/fixtures/http/** +docs/plans/011-V0_2_4_HTTP_BLOCKS_ECONOMICS_PLAN.md +ROADMAP.md +CHANGELOG.md +deltas/0.2.4/pre.002.md +``` + +Aucun delta historique n'est réécrit. + +## Validations exécutées dans le sandbox + +- contrôle différentiel contre la livraison `pre.002` ; +- vérification que seuls les trois fichiers de production listés ci-dessus sont modifiés ; +- contrôle que les 17 types publics de `pre.002` restent hors `#[cfg(test)]` ; +- contrôle que tous les helpers et structs privés signalés `dead_code` par les validations locales sont maintenant test-only ; +- contrôle de l'absence de `#[allow(dead_code)]` ; +- contrôle de l'absence de `unwrap`, `expect`, `panic!` et `unsafe` dans les lignes modifiées ; +- `git diff --check` sur le fix ; +- contrôle des versions de fichiers modifiés. + +## Validations Cargo non exécutées dans le sandbox + +Le sandbox ne fournit pas `cargo`, `rustc` ni `rustfmt`. Les validations du fix doivent donc être rejouées sur le checkout de développement : + +```bash +cargo fmt --all +cargo check --workspace +cargo clippy --workspace --all-targets +cargo test -p ksp-onchain-transport-lib +``` + +Le critère de clôture du fix est plus strict que pour la tentative initiale : `cargo check` et `cargo clippy` doivent terminer sans les 29 warnings `dead_code` introduits par `pre.002`. + +Le commit attendu après validation est : + +```text +v0.2.4-pre.002-fix.001 +``` + +## Décisions prises + +- conserver les DTOs publics actifs en production ; +- rendre test-only uniquement l'infrastructure wire interne sans consommateur runtime ; +- ne pas masquer les warnings avec `allow(dead_code)` ; +- activer progressivement les helpers lors de l'arrivée de chaque wrapper ; +- ne pas modifier le plan `011`, le périmètre fonctionnel restant identique. + +## Questions ouvertes + +Aucune. + +## Suite + +Après validation du fix, `0.2.4-pre.003` reste inchangé : + +```text +getBlockCommitment +getBlockHeight +getBlockTime +getFirstAvailableBlock +minimumLedgerSlot +```