v0.2.4-pre.008
This commit is contained in:
474
deltas/0.2.4/pre.008.md
Normal file
474
deltas/0.2.4/pre.008.md
Normal file
@@ -0,0 +1,474 @@
|
||||
<!-- file: deltas/0.2.4/pre.008.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# 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<String>,
|
||||
config: Option<RpcEpochConfig>,
|
||||
) -> Vec<Option<RpcInflationReward>>
|
||||
```
|
||||
|
||||
`RpcEpochConfig` contient :
|
||||
|
||||
```text
|
||||
epoch: Option<u64>
|
||||
commitment: Option<CommitmentConfig>
|
||||
minContextSlot: Option<u64>
|
||||
```
|
||||
|
||||
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<u8>,
|
||||
commission_bps: Option<u16>,
|
||||
}
|
||||
```
|
||||
|
||||
KSP conserve donc deux informations indépendantes :
|
||||
|
||||
```text
|
||||
commission -> Option<u8>
|
||||
commissionBps -> SolanaWireField<u16>
|
||||
```
|
||||
|
||||
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<T>` 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<Vec<Option<SolanaInflationReward>>>
|
||||
```
|
||||
|
||||
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
|
||||
```
|
||||
Reference in New Issue
Block a user