Files
2026-08-18 20:12:46 +02:00

332 lines
14 KiB
Markdown

<!-- file: deltas/0.2.4/pre.002.md -->
<!-- version: 1 -->
# Delta `0.2.4-pre.002` — primitives Blocks/Economics et fixtures wire partagées
## Base requise
Livraison précédente :
```text
0.2.4-pre.001-fix.001
workspace.package.version = "0.2.4-pre.1"
```
Le plan canonique est `docs/plans/011-V0_2_4_HTTP_BLOCKS_ECONOMICS_PLAN.md` version 2. Le fix `pre.001-fix.001` est appliqué avant cette tranche ; les deltas historiques `pre.001.md` et `pre.001-fix.001.md` restent inchangés.
## Objectif
Installer les primitives, configurations et résultats partagés nécessaires aux 10 wrappers Blocks et 5 wrappers Economics de `0.2.4`, ainsi que leurs fixtures wire locales déterministes, sans encore implémenter les wrappers prévus à partir de `pre.003` et sans déclarer la couverture typed `V0_2_4` complète.
Cette tranche matérialise dès maintenant les exigences `KSP-TRANSPORT-007` qui appartiennent au wire partagé : omissions/null explicites, versions de transaction numériques génériques, reward partitions SIMD-0118, commissions basis-points SIMD-0291, adresses RPC typées en `Pubkey` et sous-arbres Transaction riches conservés losslessly.
## Version Cargo
Conformément à `VER-ID-009`, la nouvelle prerelease synchronise le signal technique :
```text
0.2.4-pre.1 -> 0.2.4-pre.2
```
Aucune dépendance ni feature Cargo n'est ajoutée ou modifiée.
## Implémentation
### Module Blocks partagé
Le nouveau module privé `rpc_blocks` ajoute les types publics suivants, réexportés explicitement depuis la racine de crate :
```text
SolanaTransactionDetails
SolanaGetBlockConfig
SolanaBlockProductionRange
SolanaBlockProductionConfig
SolanaBlockCommitment
SolanaBlockProductionResultRange
SolanaBlockProduction
SolanaBlockReward
SolanaBlockTransaction
SolanaConfirmedBlock
SolanaPerformanceSample
```
`SolanaTransactionDetails` couvre exactement les quatre valeurs wire modernes :
```text
full
signatures
none
accounts
```
`SolanaGetBlockConfig` conserve indépendamment les cinq options du contrat moderne :
```text
commitment
encoding
transactionDetails
maxSupportedTransactionVersion
rewards
```
Aucune validation de commitment ni aucun choix de forme legacy n'est encore exécuté ici : ces responsabilités appartiennent au wrapper `getBlock` de `pre.006`.
`SolanaBlockProductionConfig` conserve `commitment`, une `identity` typée `Pubkey` et une range `firstSlot/lastSlot?`. La validation `lastSlot >= firstSlot` reste volontairement réservée au wrapper `getBlockProduction` de `pre.005`.
`SolanaBlockProduction` décode les clés dynamiques de `byIdentity` en `Pubkey` et conserve les couples `(leader slots, blocks produced)` ainsi que la range effective retournée par le runtime. Le futur wrapper appliquera le `SolanaRpcResponse<T>` partagé autour de ce résultat.
### Wire `getBlock`
`SolanaConfirmedBlock` est un DTO bloc dédié et ne réutilise pas `SolanaConfirmedTransaction`, dont `slot` et `blockTime` sont propres au top-level de `getTransaction`.
Le bloc conserve :
```text
previousBlockhash
blockhash
parentSlot
transactions
signatures
rewards
numRewardPartitions
blockTime
blockHeight
```
Les champs conditionnels `transactions`, `signatures`, `rewards` et `numRewardPartitions` utilisent `SolanaWireField<T>` afin de préserver les trois états :
```text
Omitted
Null
Value(T)
```
`numRewardPartitions` couvre explicitement le wire associé à SIMD-0118 sans synthétiser une valeur `0` en cas d'omission ou de `null`.
`SolanaBlockTransaction` compose les primitives Transaction déjà acquises :
```text
SolanaEncodedTransaction
SolanaWireField<serde_json::Value> pour meta
SolanaWireField<SolanaTransactionVersion> pour version
```
Le décodeur interne `SolanaTransactionVersion::decode_wire` passe donc de privé à `pub(crate)` pour être réutilisé sans dupliquer la logique `legacy | u8`. Son comportement public reste inchangé. Une fixture `getBlock` porte volontairement la version numérique `1` afin d'empêcher une future régression qui bornerait artificiellement cette primitive à V0, conformément au watchpoint SIMD-0385.
`SolanaBlockReward` conserve :
```text
pubkey: Pubkey
lamports: i64
postBalance: u64
rewardType: String ou null
commission: u8 ou null
commissionBps: SolanaWireField<u16>
```
`commissionBps` couvre l'extension stable déjà exposée par le runtime pour SIMD-0291. `commission` et `commissionBps` restent indépendants ; Transport ne dérive jamais l'un depuis l'autre.
`rewardType` reste volontairement une chaîne nullable au niveau Transport. Cette tranche n'introduit pas une taxonomie économique KSP spéculative alors que les évolutions de reward semantics restent dans la watchlist, notamment SIMD-0123.
### Module Economics partagé
Le nouveau module privé `rpc_economics` ajoute et réexporte :
```text
SolanaInflationGovernor
SolanaInflationRate
SolanaInflationRewardConfig
SolanaInflationReward
SolanaSupplyConfig
SolanaSupply
```
`SolanaInflationGovernor` et `SolanaInflationRate` conservent directement les valeurs runtime `f64`/epoch sans reproduire localement les formules d'inflation.
`SolanaInflationRewardConfig` sérialise uniquement les options fournies :
```text
epoch
commitment
minContextSlot
```
`SolanaInflationReward` conserve `commission: Option<u8>` et `commissionBps: SolanaWireField<u16>` pour couvrir SIMD-0291 sans perdre la différence omission/null/présent du champ basis-points. La cardinalité et les `null` positionnels de la liste `getInflationReward` seront pris en charge par le wrapper de `pre.008`; le DTO de cette tranche représente uniquement une entrée non-null.
`SolanaSupplyConfig` utilise `Option<bool>` pour `excludeNonCirculatingAccountsList`. Cela distingue un champ omis d'un `false` explicitement envoyé, tout en laissant le runtime appliquer son défaut lorsque l'option est absente.
`SolanaSupply` convertit la liste ordonnée `nonCirculatingAccounts` en `Vec<Pubkey>` et échoue proprement si une clé retournée n'est pas une public key valide. Le futur wrapper réutilisera `SolanaRpcResponse<SolanaSupply>`.
### Frontières conservées
Cette prerelease n'ajoute aucun `impl HttpTransportPool` pour les 15 méthodes `V0_2_4`. Les nouveaux types sont donc uniquement des contrats wire/config/result partagés.
Le flux d'exécution reste inchangé :
```text
wrapper typed futur
-> descriptor central
-> execute_standard_rpc
-> pool/admission
-> executor HTTP
-> validation JSON-RPC
-> decode typed
```
Aucun client HTTP parallèle, aucune boucle de retry locale et aucune dépendance Solana RPC haut niveau ne sont introduits.
## Fixtures déterministes ajoutées
```text
crates/ksp-onchain-transport-lib/fixtures/http/block_commitment.variants.json
crates/ksp-onchain-transport-lib/fixtures/http/block_production.v4_2_1.json
crates/ksp-onchain-transport-lib/fixtures/http/confirmed_block.v4_2_1.json
crates/ksp-onchain-transport-lib/fixtures/http/confirmed_block.omissions.json
crates/ksp-onchain-transport-lib/fixtures/http/performance_sample.variants.json
crates/ksp-onchain-transport-lib/fixtures/http/inflation_governor.v4_2_1.json
crates/ksp-onchain-transport-lib/fixtures/http/inflation_rate.v4_2_1.json
crates/ksp-onchain-transport-lib/fixtures/http/inflation_reward.variants.json
crates/ksp-onchain-transport-lib/fixtures/http/supply.v4_2_1.json
```
Elles couvrent notamment :
- block commitment présent et `null` ;
- `getBlockProduction.byIdentity` et la range effective ;
- bloc riche avec transaction version numérique `1` ;
- `meta` explicite `null` et version omise ;
- reward `commissionBps` présent puis omis ;
- `numRewardPartitions` présent, omis et explicitement `null` ;
- performance sample courant puis ancien sans `numNonVoteTransactions` ;
- inflation governor/rate ;
- liste inflation reward avec un `null` positionnel et les variantes `commissionBps` ;
- supply avec liste ordonnée de public keys.
## Tests ajoutés
`unit_tests/rpc_blocks.rs` ajoute **8 tests déterministes** couvrant configs, résultats, omissions/null, version transaction non nulle, extensions SIMD et validation des public keys.
`unit_tests/rpc_economics.rs` ajoute **6 tests déterministes** couvrant configs, inflation values, reward basis-points, `null` positionnel de fixture, supply ordonnée et invalid pubkey.
Les tests d'intégration ajoutent aussi :
- une canarie de surface publique qui vérifie que les 17 nouveaux types sont disponibles depuis la racine de crate ;
- une canarie de registre qui confirme que `V0_2_4` reste exactement composé des **10 Blocks + 5 Economics**, tous `Read / RetrySafe`, et que `getBlock` conserve son marqueur de forme legacy dépréciée sans prétendre que les wrappers existent déjà.
La canarie typed-complete `V0_2_4 == 15` reste volontairement fermée jusqu'aux tranches d'implémentation des wrappers.
## Fichiers ajoutés
```text
crates/ksp-onchain-transport-lib/src/rpc_blocks.rs
crates/ksp-onchain-transport-lib/src/rpc_economics.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/fixtures/http/block_commitment.variants.json
crates/ksp-onchain-transport-lib/fixtures/http/block_production.v4_2_1.json
crates/ksp-onchain-transport-lib/fixtures/http/confirmed_block.v4_2_1.json
crates/ksp-onchain-transport-lib/fixtures/http/confirmed_block.omissions.json
crates/ksp-onchain-transport-lib/fixtures/http/performance_sample.variants.json
crates/ksp-onchain-transport-lib/fixtures/http/inflation_governor.v4_2_1.json
crates/ksp-onchain-transport-lib/fixtures/http/inflation_rate.v4_2_1.json
crates/ksp-onchain-transport-lib/fixtures/http/inflation_reward.variants.json
crates/ksp-onchain-transport-lib/fixtures/http/supply.v4_2_1.json
deltas/0.2.4/pre.002.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/tests/public_api.rs
crates/ksp-onchain-transport-lib/tests/release_completeness.rs
```
## Fichiers supprimés
Aucun.
## Fichiers volontairement inchangés
```text
CHANGELOG.md
ROADMAP.md
docs/plans/011-V0_2_4_HTTP_BLOCKS_ECONOMICS_PLAN.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/**
deltas/0.2.4/pre.001.md
deltas/0.2.4/pre.001-fix.001.md
```
Aucun ancien delta n'est réécrit. Aucun wrapper Blocks/Economics n'est avancé prématurément.
## Validations exécutées dans le sandbox
- reconstruction exacte de la base `v0.2.3` puis application des overlays `0.2.4-pre.001` et `0.2.4-pre.001-fix.001` ;
- contrôle différentiel de la tranche `pre.002` contre cette base ;
- recoupement ciblé des configs/résultats avec la baseline Agave `v4.2.1` retenue par le plan ;
- parse JSON local des neuf nouvelles fixtures ;
- contrôle statique des 17 réexports crate-root ;
- contrôle statique que chaque nouveau item `pub`/`pub(crate)` de production possède sa documentation ;
- contrôle statique de l'absence de `impl HttpTransportPool` dans les nouveaux modules ;
- contrôle statique de l'absence de `use`, `unwrap`, `expect`, `panic!` et opérateur `?` dans les deux nouvelles sources de production ;
- contrôle statique des lignes Rust modifiées à `<= 160` colonnes ;
- contrôle différentiel de `Cargo.toml` : seul `workspace.package.version` change ;
- contrôle différentiel de `rpc_transactions.rs` : seule la version de fichier et la visibilité interne documentée de `SolanaTransactionVersion::decode_wire` changent ;
- contrôle que `CHANGELOG.md`, `ROADMAP.md`, le plan `011` version 2 et les deltas historiques restent inchangés.
## Validations Cargo non exécutées
Le sandbox courant ne fournit pas `cargo`, `rustc` 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 graphes complets restent obligatoires à la clôture `pre.009`.
Le commit attendu après application et validations suit `VER-GIT-001` :
```text
v0.2.4-pre.002
```
## Décisions prises
- séparer physiquement les primitives Blocks et Economics dans deux modules Transport dédiés ;
- ne pas avancer de wrapper avant sa tranche propriétaire ;
- réutiliser `SolanaWireField<T>`, `SolanaEncodedTransaction` et `SolanaTransactionVersion` plutôt que dupliquer le wire Transaction ;
- ouvrir uniquement la visibilité interne de `SolanaTransactionVersion::decode_wire` sans modifier son API publique ;
- typer les identités/adresses RPC en `Pubkey` lorsqu'elles sont structurelles ;
- garder les sous-arbres Transaction/meta riches lossless via `serde_json::Value` ;
- garder `rewardType` ouvert au niveau Transport au lieu d'introduire une taxonomie économique prématurée ;
- distinguer `excludeNonCirculatingAccountsList` omis d'un `false` explicite ;
- intégrer dès les fixtures partagées SIMD-0118, SIMD-0291 et la canarie future-compatible SIMD-0385 ;
- ne pas modifier le plan `011`, aucune capacité stable additive n'ayant été découverte pendant cette tranche.
## Questions ouvertes
Aucune question bloquante pour `pre.003`.
## Suite
`0.2.4-pre.003` : implémenter les cinq wrappers Blocks simples avec requêtes JSON exactes et réponses typed :
```text
getBlockCommitment
getBlockHeight
getBlockTime
getFirstAvailableBlock
minimumLedgerSlot
```