Files
khadhroony-solana-project/docs/architecture/006-WIRE_AND_PROGRAM.md
2026-08-14 09:51:30 +02:00

419 lines
14 KiB
Markdown

<!-- file: docs/architecture/006-WIRE_AND_PROGRAM.md -->
<!-- version: 1 -->
# Wire, Program API et implémentations Program
## Objet
Ce document constitue la sortie principale de `0.0.3-pre.004`.
Il précise :
- le rôle de `ksp-interface-lib` ;
- la propriété des codecs wire ;
- la politique de sélection/réimplémentation des crates d'interface externes ;
- la forme générale et ouverte de `ksp-program-api` ;
- la séparation decoder / préparation d'exécution ;
- le registry extensible ;
- l'organisation interne prévue de `ksp-program-lib` ;
- le workflow d'une implémentation de programme développée hors de l'implémentation officielle.
Les types Rust exacts restent volontairement à définir lors de la première implémentation réelle.
## `ksp-interface-lib`
`ksp-interface-lib` est la façade wire officielle KSP pour les programmes Solana supportés officiellement.
Elle possède ou réexporte de manière contrôlée les contrats nécessaires tels que :
- discriminants ;
- layouts d'instructions ;
- layouts de comptes ;
- enums/structures wire ;
- sérialisation/désérialisation wire ;
- règles et seeds de PDA lorsque ces règles appartiennent au contrat protocolaire ;
- constructeurs d'instructions lorsque ceux-ci représentent directement le contrat wire.
Les Program IDs fondamentaux restent possédés par `ksp-core-lib`.
`ksp-interface-lib` ne possède pas :
- RPC/WS/provider ;
- wallet/signature ;
- persistence ;
- matérialisation ;
- interprétation canonique/métier d'une instruction ;
- policy/safety ;
- lifecycle d'exécution réseau.
## Propriété des codecs wire
Pour le code KSP officiel, les dépendances directement utilisées pour encoder/décoder les formats wire, notamment `borsh`, `wincode` ou codecs équivalents, appartiennent normalement à `ksp-interface-lib`.
La règle n'interdit pas qu'une autre crate KSP utilise un codec pour une raison indépendante du wire Solana, mais une telle dépendance directe doit avoir une justification distincte.
En particulier :
```text
ksp-interface-lib
-> borsh / wincode / codecs wire nécessaires
ksp-program-lib
-X-> borsh / wincode pour redécoder directement le wire protocolaire
```
`ksp-program-lib` reçoit des contrats typés/wire exposés par la façade officielle au lieu de recréer la sérialisation protocolaire.
## Politique de sélection des interfaces externes
Une crate externe d'interface Solana/Anza peut être utilisée directement lorsque :
1. elle appartient à une source officielle ou suffisamment normative pour le contrat concerné ;
2. sa surface est suffisamment stable et finale pour l'usage KSP ;
3. son graphe de dépendances est compatible avec le stack de dépendances KSP actuel ;
4. elle n'introduit pas sans nécessité une génération ancienne/incompatible d'un codec ou d'une primitive fondamentale ;
5. son usage évite une réimplémentation KSP sans réduire le contrôle du contrat public.
Une crate protocolaire externe peut être rejetée même si son API fonctionne lorsqu'elle impose un stack ancien ou incompatible avec le reste du workspace.
### Exemples observés pendant la planification
`solana-loader-v3-interface` illustre une interface officielle actuelle qui peut raisonnablement être conservée plutôt que réécrite lorsque sa version et son graphe restent compatibles avec KSP.
`mpl-token-metadata` illustre le cas inverse : KSP ne prévoit pas de l'intégrer comme dépendance runtime. Les contrats wire Metaplex Token Metadata nécessaires seront réimplémentés/possédés par `ksp-interface-lib`.
Ces exemples sont des applications de la règle, pas des exceptions codées en dur : l'état des dépendances doit être revérifié au moment de chaque implémentation.
## Politique anti-doublons de générations
KSP ne cherche pas à figer arbitrairement une version précise des dépendances. Le projet cherche au contraire à rester sur des générations récentes et compatibles.
Les doublons de versions/générations de dépendances fondamentales doivent être inspectés régulièrement, notamment pour :
- codecs wire ;
- primitives Solana ;
- sérialisation ;
- bibliothèques cryptographiques fondamentales.
Un doublon réellement imposé et inévitable par une dépendance retenue peut être temporairement accepté avec justification.
Un doublon évitable provoqué par une crate protocolaire remplaçable doit être éliminé plutôt que normalisé comme dette permanente.
Outils d'audit attendus lorsque le workspace fonctionnel le permettra :
```bash
cargo tree -d
cargo tree -i borsh
cargo tree -i wincode
```
La liste sera complétée selon les dépendances réellement utilisées.
## `ksp-program-api`
`ksp-program-api` porte des contrats publics **ouverts**.
Une implémentation externe doit pouvoir prendre en charge un Program ID encore inconnu de `ksp-program-lib` sans modifier une enum centrale KSP.
### Pas d'enum fermée de programmes
Une structure de la forme suivante est explicitement évitée :
```text
enum DecodedProgram {
Token(...),
Token2022(...),
Meteora(...),
...
}
```
car chaque nouveau protocole exigerait une modification de l'API centrale.
De même, un `Any` runtime non persistable ne peut pas constituer l'unique représentation d'un résultat décodé.
Le résultat doit rester :
- auto-identifiable ;
- extensible ;
- sérialisable/persistable lorsque la frontière Core l'exige ;
- exploitable par une implémentation externe de materializer ;
- compatible avec l'ajout de Program IDs sans modification de l'API commune.
La représentation exacte du payload ouvert sera définie avec les contrats Core/Store/Materializer réels, sans introduire prématurément une enum fermée.
## Familles de decoders
Plutôt qu'un unique trait possédant toutes les surfaces possibles, `ksp-program-api` doit pouvoir distinguer les capacités de décodage.
Familles initiales candidates :
```text
ProgramInstructionDecoder
ProgramAccountDecoder
ProgramEventDecoder
ProgramReturnDataDecoder
```
Les deux premières sont considérées comme besoins fondamentaux probables.
Les autres ne sont ajoutées que lorsqu'une première surface réelle le justifie.
Une implémentation de programme n'est pas obligée de fournir toutes les capacités.
Des descripteurs communs doivent permettre d'identifier les capacités effectivement supportées.
## Politique de décodage historique
Le decoder vise toute surface techniquement décodable dont la définition est connue :
- actuelle ;
- ancienne ;
- legacy ;
- abandonnée ;
- expérimentale/test lorsque le wire est connu ;
- historique distinguable.
Le statut de lifecycle d'une opération n'empêche jamais son décodage historique.
Si une définition a réellement été écrasée sous une identité indistinguable et que l'ancienne forme ne peut plus être reconnue de manière fiable, la définition applicable la plus récente est utilisée.
Le concept `deprecated` n'est donc pas un filtre de decoder.
## Préparation d'exécution Program
Le terme `ProgramExecutor` est abandonné dans le cadrage KSP parce qu'il suggère une exécution transactionnelle complète.
Le contrat prévu est nommé conceptuellement :
```text
ProgramExecutionPreparer
```
Sa responsabilité :
```text
ProgramExecutionRequest
|
v
ProgramExecutionPreparer
|
v
PreparedProgramExecution
```
Noms exacts des types à confirmer lors de l'implémentation.
Le preparer peut notamment :
- valider les paramètres protocolaires ;
- déterminer les comptes requis ;
- dériver les PDA nécessaires ;
- construire une ou plusieurs instructions ;
- indiquer les autorités/signers requis ;
- exposer les contraintes techniques propres à l'opération.
Il ne réalise pas :
- sélection du wallet réel ;
- accès aux secrets ;
- récupération du recent blockhash ;
- signature transactionnelle ;
- simulation RPC ;
- envoi réseau ;
- confirmation ;
- retry réseau ;
- policy/safety de produit.
Ces responsabilités appartiennent aux couches d'exécution supérieures.
## `PreparedProgramExecution`
Le contrat préparé entre Program et Execution doit pouvoir transporter conceptuellement :
- identité du programme/opération ;
- instructions ;
- comptes/authorities/signers requis ;
- contraintes techniques ;
- informations nécessaires à une policy supérieure ;
- metadata de préparation utiles à l'exécution.
Il ne contient pas de secret wallet et ne fixe pas un endpoint réseau concret.
Il doit être consommable par `ksp-execution-lib` indépendamment du fait que l'implémentation Program provienne de `ksp-program-lib` ou d'une crate externe.
## Lifecycle des opérations préparables
Le lifecycle d'une opération d'exécution doit être machine-readable.
Il faut distinguer au minimum conceptuellement :
- opération actuelle/supportée ;
- opération legacy/ancienne mais pas nécessairement déconseillée ;
- opération réellement abandonnée/déconseillée.
Les noms exacts des statuts seront définis plus tard.
Le statut « deprecated » est réservé à une surface clairement abandonnée/remplacée, pas simplement ancienne.
KSP ne rend pas obligatoire l'annotation Rust `#[deprecated]`.
Une opération techniquement encore préparée mais marquée comme abandonnée peut :
1. produire un warning explicite ;
2. transmettre son statut à `ksp-execution-policy-api` ;
3. être autorisée ou rejetée par la policy supérieure selon le contexte.
Le decoder continue de la reconnaître indépendamment de ce statut.
## Registry extensible
Le registry Program doit pouvoir combiner :
- implémentations officielles KSP ;
- implémentations externes ;
- implémentations expérimentales.
Les descripteurs doivent permettre d'identifier au minimum conceptuellement :
- Program ID ;
- identité/version de l'implémentation ;
- capacités de décodage ;
- opérations préparables ;
- statut/lifecycle des opérations ;
- autres capacités nécessaires au dispatch.
Le contrat exact du registry sera défini lors de l'implémentation.
Le registry ne doit pas nécessiter une modification de `ksp-program-api` pour enregistrer un nouveau Program ID.
## Implémentations externes
Une extension externe de programme est une **implémentation** de `ksp-program-api`, pas une nouvelle API commune.
Nomenclature recommandée lorsque l'extension suit les conventions KSP :
```text
ksp-program-<name>-lib
```
Exemple conceptuel :
```text
ksp-program-fluxbeam-lib
```
et non :
```text
ksp-program-fluxbeam-api
```
Cette crate peut dépendre de :
```text
ksp-program-api
ksp-core-lib
ksp-interface-lib
```
selon les besoins.
Elle peut être développée, testée et utilisée par un runtime KSP sans être intégrée à `ksp-program-lib`.
## Wire d'une extension encore non officielle
`ksp-interface-lib` est la façade wire **officielle KSP**, mais `ksp-program-api` ne doit pas empêcher une extension externe de fournir temporairement ses propres définitions wire.
Deux cas sont possibles :
```text
interface officielle déjà dans KSP
-> extension utilise ksp-interface-lib
interface pas encore intégrée
-> extension possède sa définition wire compatible
-> extension implémente ksp-program-api
```
Lors de l'intégration officielle :
1. les définitions wire sont revues/vérifiées ;
2. les contrats wire nécessaires migrent vers `ksp-interface-lib` ;
3. decoder/preparer migrent vers `ksp-program-lib` ;
4. le contrat `ksp-program-api` ne change pas pour cette seule raison.
## Organisation interne de `ksp-program-lib`
`ksp-program-lib` doit être organisé d'abord par domaine puis par programme/protocole, et seulement ensuite par capacité.
Direction retenue :
```text
<domain>/
<program-or-protocol>/
dec/
...
exec_prep/
...
```
Exemples conceptuels :
```text
spl/
token_2022/
dec/
exec_prep/
metadata/
token/
mpl/
dec/
exec_prep/
dex/
meteora/
dlmm/
dec/
exec_prep/
```
Les noms courts `dec` / `exec_prep` restent une convention candidate ; les noms précis seront décidés avec les premières vraies arborescences Rust.
Le principe durable est :
```text
domain -> program/protocol -> capability
```
et non un répertoire racine géant `decoder/` ou `executor/` contenant tous les protocoles.
## Conformité wire
Pour chaque contrat wire réimplémenté, la documentation/tests doivent permettre d'identifier la source normative utilisée.
Les validations peuvent combiner selon le cas :
- documentation/source officielle ;
- fixtures officielles ;
- transactions/comptes réels connus ;
- golden vectors ;
- comparaison avec une implémentation de référence lorsqu'elle peut être utilisée sans polluer durablement le graphe KSP.
Une crate externe provoquant volontairement une génération incompatible de dépendances fondamentales ne doit pas être ajoutée au workspace simplement pour faciliter un test si des fixtures/vecteurs indépendants permettent la même vérification.
## Questions laissées ouvertes
La première implémentation Program devra encore fixer précisément :
- formes Rust des traits decoder ;
- représentation du payload décodé ouvert/persistable ;
- forme exacte des descriptors ;
- types exacts `ProgramExecutionRequest` / `PreparedProgramExecution` ;
- forme du registry et règles de conflit entre plusieurs implémentations d'un même Program ID ;
- stratégie précise de warning/log pour opérations abandonnées ;
- convention finale `dec` / `exec_prep`.
La tranche suivante doit traiter `ksp-execution-policy-api` et `ksp-execution-lib` sans rouvrir les responsabilités Program définies ici.