v0.2.4-pre.006
This commit is contained in:
541
deltas/0.2.4/pre.006.md
Normal file
541
deltas/0.2.4/pre.006.md
Normal file
@@ -0,0 +1,541 @@
|
||||
<!-- 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
|
||||
```
|
||||
Reference in New Issue
Block a user