14 KiB
Delta 0.2.4-pre.006 — getBlock complet
Base requise
Livraison précédente :
0.2.4-pre.005
workspace.package.version = "0.2.4-pre.5"
Les validations locales fournies pour cette base sont propres :
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 :
getBlock
La méthode est déjà enregistrée :
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 :
slot
Option<RpcEncodingConfigWrapper<RpcBlockConfig>>
La forme wrapper conserve donc deux familles de requêtes :
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 :
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 :
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 :
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 :
SolanaTransactionVersion::Legacy
SolanaTransactionVersion::Number(u8)
Le wrapper getBlock ajoute une canary avec :
version = 1
Il ne régresse donc pas vers un modèle limité à legacy ou v0.
Version Cargo
Nouvelle prerelease technique :
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 :
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 :
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 :
#[deprecated]
HttpTransportPool::get_block_legacy(role, slot, encoding)
Elle émet le warning KSP centralisé et encode exactement :
[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 :
full
signatures
none
accounts
Leurs conséquences wire Agave sont conservées sans synthèse :
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 :
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 :
Option<SolanaConfirmedBlock>
Le null top-level du RPC est conservé comme None.
Pour un bloc présent, KSP conserve :
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 :
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 :
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 :
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 :
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 :
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 :
rewards: false
KSP accepte donc correctement :
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 :
commitment = processed -> ERROR_CODE_INVALID_RPC_PARAMETERS avant I/O
commitment = confirmed -> autorisé
commitment = finalized -> autorisé
KSP ne tente pas de prévalider :
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 :
-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 :
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
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:falsesans disparition denumRewardPartitions;- SIMD-0118 ;
- SIMD-0291 ;
- transaction version numérique
1pour la compatibilité préparée SIMD-0385 ; - erreurs RPC bloc/version.
Tests ajoutés
Neuf unit tests HTTP sont ajoutés :
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 :
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.006de 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.009réauditera ensemble au minimum0298/0301/0307pour le futur footer.
Les deux tableaux du plan conservent leur structure source alignée :
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 :
Transport -X-> Config
Transport -X-> Store
Transport -X-> Program
Transport -X-> tracing direct
Le wrapper passe uniquement par :
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 :
cargo fmt --all
cargo check --workspace
cargo clippy --workspace --all-targets
cargo test -p ksp-onchain-transport-lib
Attendus :
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 :
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 :
15 fixtures get_block*.json
deltas/0.2.4/pre.006.md
Identifiant de commit attendu
Après validation locale :
v0.2.4-pre.006
La tranche suivante reste :
0.2.4-pre.007 — réaudit SIMD-0490/0550 + Economics simples