Files
khadhroony-solana-project/deltas/0.2.4/pre.006.md
2026-08-18 21:21:02 +02:00

542 lines
14 KiB
Markdown

<!-- file: deltas/0.2.4/pre.006.md -->
<!-- version: 1 -->
# Delta `0.2.4-pre.006` — `getBlock` complet
## Base requise
Livraison précédente :
```text
0.2.4-pre.005
workspace.package.version = "0.2.4-pre.5"
```
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 -> 212 unit tests OK
23 public API tests OK
18 release-completeness tests OK
1 smoke Devnet ignoré comme prévu
0 échec
```
## Objectif
Achever la famille Blocks de `0.2.4` avec le wrapper le plus riche de la release :
```text
getBlock
```
La méthode est déjà enregistrée :
```text
V0_2_4 / Blocks / Read / RetrySafe / StableWithDeprecatedLegacy
```
Le registre central n'est pas modifié.
Après cette tranche, les dix wrappers Blocks de `0.2.4` sont matérialisés. Les cinq wrappers Economics restent volontairement pour `pre.007` et `pre.008`.
## Réaudit primaire `getBlock` — Agave `v4.2.1`
La source runtime stable confirme que `getBlock` reçoit :
```text
slot
Option<RpcEncodingConfigWrapper<RpcBlockConfig>>
```
La forme wrapper conserve donc deux familles de requêtes :
```text
moderne : [slot, { ...RpcBlockConfig }]
legacy : [slot, "encoding"]
```
La forme legacy bare encoding reste supportée par le runtime pour backwards compatibility, mais n'est pas la forme KSP recommandée.
`RpcBlockConfig` expose exactement dans la baseline stable :
```text
encoding: Option<UiTransactionEncoding>
transactionDetails: Option<TransactionDetails>
rewards: Option<bool>
commitment: Option<CommitmentConfig>
maxSupportedTransactionVersion: Option<u8>
```
Aucun champ `footer` n'existe dans `RpcBlockConfig` stable `v4.2.1`.
Défauts appliqués côté runtime lorsqu'ils ne sont pas fournis :
```text
encoding = json
transactionDetails = full
rewards = true
```
Le commitment explicitement fourni doit être au moins `confirmed`; KSP rejette donc `processed` avant I/O avec le domaine d'erreur partagé.
## Réaudit SIMD footer / transaction version
### SIMD-0307 — Add Block Footer
Le document est toujours en `Review` et propose :
```text
config getBlock : footer
réponse : footer fields, dont blockProducerTimeNanos / blockUserAgent
```
Ces champs sont absents de la baseline Agave `v4.2.1`; ils ne sont pas inventés dans KSP.
### SIMD-0298 — Add `bank_hash` to block footer
Le document SIMD reste au statut `Idea`. Il propose un futur `bank_hash` dans le block footer. Ce champ n'existe pas dans le wire RPC stable audité et n'est pas ajouté spéculativement.
Le tracker amont lié à Bankless Leader/Alpenglow rend néanmoins ce sujet important pour le réaudit final : l'existence d'une implémentation future du mécanisme ne transforme pas sa forme RPC en contrat stable `v4.2.1`.
### SIMD-0301 — `parent_bank_hash`
Le PR SIMD-0301 proposait de remplacer `bank_hash` par `parent_bank_hash` et de supersede SIMD-0298. Il a été fermé le 28 janvier 2026 sans merge. Il ne constitue donc ni un SIMD adopté ni un wire stable.
Le plan vivant ajoute `0301` à la watchlist de `pre.009` avec `0298` et `0307`, afin de ne pas figer prématurément le nom ou même la présence d'un futur hash de footer.
### SIMD-0385 — Transaction V1
SIMD-0385 reste en `Review`, tandis que la baseline Agave `v4.2.1` possède déjà le plumbing transaction-status nécessaire aux messages V1.
KSP conserve une représentation générique :
```text
SolanaTransactionVersion::Legacy
SolanaTransactionVersion::Number(u8)
```
Le wrapper `getBlock` ajoute une canary avec :
```text
version = 1
```
Il ne régresse donc pas vers un modèle limité à `legacy` ou `v0`.
## Version Cargo
Nouvelle prerelease technique :
```text
0.2.4-pre.5 -> 0.2.4-pre.6
```
Aucune dépendance ni feature Cargo n'est ajoutée ou modifiée.
## Forme moderne
Signature publique :
```text
HttpTransportPool::get_block(
role,
slot,
Option<&SolanaGetBlockConfig>,
) -> Result<Option<SolanaConfirmedBlock>>
```
Les trois états de la config restent distingués lorsque leur forme wire est utile :
```text
None -> [slot]
Some(default config) -> [slot, {}]
Some(config) -> [slot, {...}]
```
La config moderne acquise en `pre.002` est réutilisée, sans DTO parallèle.
## Forme legacy retained
La surface publique dédiée est :
```text
#[deprecated]
HttpTransportPool::get_block_legacy(role, slot, encoding)
```
Elle émet le warning KSP centralisé et encode exactement :
```text
[slot, "binary"]
[slot, "base58"]
[slot, "base64"]
[slot, "json"]
[slot, "jsonParsed"]
```
Les cinq labels de `UiTransactionEncoding` stable sont couverts, y compris `binary`, lui-même legacy mais encore retenu par Agave pour compatibilité.
## `transactionDetails` complet
Les quatre variantes stables sont couvertes :
```text
full
signatures
none
accounts
```
Leurs conséquences wire Agave sont conservées sans synthèse :
```text
full -> transactions présent, signatures omis
signatures -> transactions omis, signatures présent
none -> transactions omis, signatures omis
accounts -> transactions présent sous représentation account-list, signatures omis
```
La représentation `accounts` reste un payload transaction JSON lossless; elle n'est pas forcée dans la structure plus riche d'une transaction `full`.
## Encodings et union transaction
Les cinq encodings modernes et legacy sont testés. Le DTO partagé `SolanaEncodedTransaction` couvre les trois formes de réponse effectivement nécessaires :
```text
LegacyBinary(String) <- encoding "binary"
Binary { data, Base58 ou Base64 } <- encodings "base58" / "base64"
Json(serde_json::Value) <- encodings "json" / "jsonParsed" et transactionDetails=accounts
```
Aucun décodage binaire, Program-specific ou message-specific n'est introduit dans Transport.
## Résultat bloc riche
`getBlock` retourne :
```text
Option<SolanaConfirmedBlock>
```
Le `null` top-level du RPC est conservé comme `None`.
Pour un bloc présent, KSP conserve :
```text
previousBlockhash
blockhash
parentSlot
transactions : SolanaWireField<Vec<SolanaBlockTransaction>>
signatures : SolanaWireField<Vec<String>>
rewards : SolanaWireField<Vec<SolanaBlockReward>>
numRewardPartitions : SolanaWireField<u64>
blockTime : Option<i64>
blockHeight : Option<u64>
```
Les champs dont la présence dépend du mode de réponse gardent donc leurs états wire `omitted` / `null` / `value` au lieu d'être normalisés.
## Transactions de bloc
Un élément `transactions[]` possède son propre DTO, distinct de `SolanaConfirmedTransaction` :
```text
transaction
meta
version
```
Le DTO de `getTransaction` n'est pas réutilisé car son `slot` et son `blockTime` sont top-level et n'appartiennent pas à chaque transaction d'un bloc.
`meta` reste :
```text
SolanaWireField<serde_json::Value>
```
Cela préserve sans perte les champs transaction-status actuels et leurs extensions, notamment les rewards imbriqués, sans transférer de logique métier dans Transport.
## Rewards et SIMD-0291
Le reward de bloc conserve :
```text
pubkey: Pubkey
lamports: i64
postBalance: u64
rewardType: Option<String>
commission: Option<u8>
commissionBps: SolanaWireField<u16>
```
`commission` et `commissionBps` restent indépendants : KSP ne dérive jamais l'un depuis l'autre.
Les fixtures couvrent :
```text
commission = null + commissionBps présent
commission présent + commissionBps omis
commissionBps imbriqué dans transaction.meta
```
## Reward partitions et SIMD-0118
`numRewardPartitions` reste un champ wire propre :
```text
SolanaWireField<u64>
```
Les fixtures couvrent `value`, omission et `null` de compatibilité. Aucun `0` n'est synthétisé.
Point important confirmé dans l'encodeur Agave : `numRewardPartitions` est renseigné depuis le bloc indépendamment de `show_rewards`. Avec :
```text
rewards: false
```
KSP accepte donc correctement :
```text
rewards omis
numRewardPartitions présent
```
sans lier artificiellement les deux champs.
## Rewards désactivés dans `meta`
Le runtime Agave n'utilise pas exactement la même sérialisation interne selon les chemins `full/jsonParsed`, `accounts`, etc. pour masquer les rewards de metadata.
Transport ne normalise pas ces sous-arbres. La fixture `full` avec `rewards:false` conserve explicitement un `meta.rewards = null`, tandis que les formes qui omettent ce champ restent également préservées grâce au `serde_json::Value` lossless.
## Validation déterministe avant I/O
La seule validation locale ajoutée à `getBlock` est :
```text
commitment = processed -> ERROR_CODE_INVALID_RPC_PARAMETERS avant I/O
commitment = confirmed -> autorisé
commitment = finalized -> autorisé
```
KSP ne tente pas de prévalider :
```text
disponibilité du bloc
slot cleaned/skipped
historique local ou long-term storage
support réel d'une version de transaction par le caller/runtime
```
Ces états appartiennent au runtime RPC.
## Erreurs RPC runtime préservées
Deux erreurs Agave caractéristiques sont couvertes par fixtures :
```text
-32004 BlockNotAvailable
-32015 UnsupportedTransactionVersion
```
Toutes deux restent des `ERROR_CODE_RPC_APPLICATION_ERROR` dans la façade KSP; elles ne sont ni transformées en erreurs de validation locale ni avalées en `None`.
Le `null` success result reste distinct d'une erreur RPC.
## Discipline `#[cfg(test)]`
La règle introduite par `pre.002-fix.001` reste appliquée.
Deviennent runtime dans cette tranche parce que `getBlock` les consomme réellement :
```text
SolanaGetBlockConfig::to_json_value
SolanaBlockReward::decode_wire
SolanaBlockTransaction::decode_wire
SolanaConfirmedBlock::decode_wire
decode_block_transaction_version
decode_block_transactions
decode_block_rewards
WireBlockReward
WireBlockTransaction
WireConfirmedBlock
```
`SolanaGetBlockConfig::is_empty` reste test-only : le wrapper doit justement préserver un `Some(default config)` explicite comme `{}` et n'a aucun besoin runtime de le canoniser.
Les helpers Economics restent test-only jusqu'à `pre.007`/`pre.008`.
Aucun `#[allow(dead_code)]` n'est introduit.
## Fixtures HTTP ajoutées
```text
get_block.full.success.json
get_block.full_no_rewards.success.json
get_block.signatures.success.json
get_block.none.success.json
get_block.accounts.success.json
get_block.binary.success.json
get_block.base58.success.json
get_block.base64.success.json
get_block.json.success.json
get_block.json_parsed.success.json
get_block.null.json
get_block.omitted_fields.success.json
get_block.null_fields.success.json
get_block.error_block_not_available.json
get_block.error_unsupported_version.json
```
Elles couvrent notamment :
- rich full wire ;
- cinq encodings ;
- quatre `transactionDetails` ;
- legacy bare encoding ;
- result `null` ;
- états omitted/null/value des champs top-level conditionnels ;
- `rewards:false` sans disparition de `numRewardPartitions` ;
- SIMD-0118 ;
- SIMD-0291 ;
- transaction version numérique `1` pour la compatibilité préparée SIMD-0385 ;
- erreurs RPC bloc/version.
## Tests ajoutés
Neuf unit tests HTTP sont ajoutés :
```text
typed_get_block_modern_full_config_preserves_rich_wire_and_simd_fields
typed_get_block_preserves_absent_and_explicit_empty_modern_config
typed_get_block_legacy_covers_all_bare_encoding_labels_and_response_shapes
typed_get_block_modern_covers_all_agave_v4_2_1_encoding_labels
typed_get_block_covers_full_signatures_none_and_accounts_transaction_details
typed_get_block_preserves_null_and_omitted_top_level_wire_states
typed_get_block_preserves_unsupported_version_rpc_error
typed_get_block_preserves_block_not_available_rpc_error
typed_get_block_rejects_processed_commitment_before_io
```
Une canary public API est ajoutée pour les deux formes publiques moderne/legacy et les getters de config.
Une canary release-completeness vérifie désormais que la famille Blocks `V0_2_4` possède exactement ses dix descriptors `Read / RetrySafe` et que `getBlock` conserve son marqueur `StableWithDeprecatedLegacy`.
Compteurs attendus après validation :
```text
221 unit tests
24 public API tests
19 release-completeness tests
1 smoke Devnet ignoré
```
## Documentation vivante
`docs/plans/011-V0_2_4_HTTP_BLOCKS_ECONOMICS_PLAN.md` passe en version 4.
Modifications :
- réaudit `pre.006` de SIMD-0298/0307 ;
- ajout de SIMD-0301 à la watchlist finale après constat de fermeture sans merge ;
- ajout des sources Agave transaction-status/custom-error effectivement utilisées pour vérifier le wire riche et les erreurs ;
- `pre.009` réauditera ensemble au minimum `0298/0301/0307` pour le futur footer.
Les deux tableaux du plan conservent leur structure source alignée :
```text
19 lignes au total
4 colonnes
5 caractères `|` par ligne
largeurs 31 / 152 / 163 / 302
```
Aucun ancien delta n'est modifié.
## Frontières architecturales
Cette tranche ne change aucune frontière :
```text
Transport -X-> Config
Transport -X-> Store
Transport -X-> Program
Transport -X-> tracing direct
```
Le wrapper passe uniquement par :
```text
getBlock typed
-> descriptor central
-> execute_standard_rpc
-> admission/pool/executor HTTP commun
-> parser JSON-RPC central
-> decode typed/lossless
```
Aucun client RPC Solana haut niveau, reqwest parallèle, retry local ou décodage Program n'est ajouté.
## Validation attendue
Après application :
```bash
cargo fmt --all
cargo check --workspace
cargo clippy --workspace --all-targets
cargo test -p ksp-onchain-transport-lib
```
Attendus :
```text
0 warning introduit
221 unit tests OK
24 public API tests OK
19 release-completeness tests OK
1 smoke Devnet ignoré comme prévu
0 échec
```
Le sandbox d'échange ne possède pas de toolchain Rust ; ces validations compilées doivent donc être confirmées localement.
## Fichiers touchés
Modifiés :
```text
Cargo.toml
crates/ksp-onchain-transport-lib/src/rpc_blocks.rs
crates/ksp-onchain-transport-lib/unit_tests/rpc_blocks.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
```
Ajoutés :
```text
15 fixtures get_block*.json
deltas/0.2.4/pre.006.md
```
## Identifiant de commit attendu
Après validation locale :
```text
v0.2.4-pre.006
```
La tranche suivante reste :
```text
0.2.4-pre.007 — réaudit SIMD-0490/0550 + Economics simples
```