v0.2.13-pre.007
This commit is contained in:
@@ -1,19 +1,109 @@
|
||||
<!-- file: crates/ksp-interface-lib/README.md -->
|
||||
<!-- version: 1 -->
|
||||
<!-- version: 2 -->
|
||||
|
||||
# ksp-interface-lib
|
||||
|
||||
`ksp-interface-lib` est la façade KSP destinée aux contrats wire passifs des programmes Solana. Elle est conçue pour être consommée par les implémentations Program officielles ou externes sans absorber Transport, Wallet, Store, Config ni le comportement métier Program.
|
||||
`ksp-interface-lib` est la façade wire officielle KSP destinée aux contrats passifs partagés par les implémentations Program Solana officielles ou externes. La crate expose uniquement des structures de représentation/admission ; elle ne possède ni transport, ni exécution, ni persistence, ni comportement métier Program.
|
||||
|
||||
## Ownership
|
||||
|
||||
La crate réutilise les primitives fondamentales déjà possédées par `ksp-core-lib`, notamment `Pubkey`. Les Program IDs fondamentaux restent également dans Core. Interface possédera progressivement les layouts, discriminants, codecs et constructeurs wire uniquement lorsqu'un protocole réel les exige.
|
||||
La crate réutilise les primitives fondamentales déjà possédées par `ksp-core-lib` :
|
||||
|
||||
La foundation ne dépend pas de runtime réseau ou applicatif. Elle n'ajoute donc pas de logging runtime, de scheduler, de persistence ou de configuration.
|
||||
```text
|
||||
Pubkey
|
||||
Error / ErrorCode / Result
|
||||
Program IDs fondamentaux
|
||||
```
|
||||
|
||||
## Surface initiale
|
||||
`Pubkey` est réexporté depuis le crate-root Interface afin qu'un consumer wire n'introduise aucun wrapper d'identité parallèle. Les Program IDs restent possédés et répertoriés par Core.
|
||||
|
||||
La façade crate-root expose actuellement le `Pubkey` canonique de Core. Les contrats passifs d'instruction et d'account meta sont introduits séparément afin de fermer leurs bornes et leur surface publique avant les premières APIs Program.
|
||||
La dependency direction candidate `0.2.13` reste strictement :
|
||||
|
||||
```text
|
||||
ksp-interface-lib
|
||||
└── ksp-core-lib
|
||||
└── solana-pubkey
|
||||
```
|
||||
|
||||
## Surface publique `0.2.13`
|
||||
|
||||
La façade crate-root expose exactement :
|
||||
|
||||
```text
|
||||
Pubkey
|
||||
ProgramAccountMeta
|
||||
MAX_PROGRAM_INSTRUCTION_ACCOUNTS
|
||||
ProgramInstruction
|
||||
MAX_PROGRAM_INSTRUCTION_DATA_LEN
|
||||
ERROR_CODE_PROGRAM_INSTRUCTION_LIMIT_EXCEEDED
|
||||
```
|
||||
|
||||
Aucun module interne n'est public.
|
||||
|
||||
### `ProgramAccountMeta`
|
||||
|
||||
`ProgramAccountMeta` représente un compte ordonné d'une instruction avec :
|
||||
|
||||
```text
|
||||
pubkey
|
||||
is_signer
|
||||
is_writable
|
||||
```
|
||||
|
||||
Les champs restent privés. Les constructeurs publics sont `readonly(pubkey, is_signer)` et `writable(pubkey, is_signer)`, complétés par les accessors `pubkey()`, `is_signer()` et `is_writable()`.
|
||||
|
||||
La structure n'applique aucune sémantique spécifique à un programme et n'exige pas que la `Pubkey` appartienne au registry des Program IDs Core.
|
||||
|
||||
### `ProgramInstruction`
|
||||
|
||||
`ProgramInstruction` représente un contrat passif borné :
|
||||
|
||||
```text
|
||||
program_id
|
||||
accounts: Vec<ProgramAccountMeta>
|
||||
data: Vec<u8>
|
||||
```
|
||||
|
||||
`ProgramInstruction::try_new` consomme directement les deux `Vec`, conserve l'ordre et les doublons des accounts et préserve les octets opaques de `data` sans décodage.
|
||||
|
||||
Les cas vides sont valides et une `program_id` inconnue du registry KSP reste admissible.
|
||||
|
||||
## Bornes d'admission
|
||||
|
||||
Interface applique deux limites locales :
|
||||
|
||||
| Limite | Valeur |
|
||||
|------------------------------------|----------|
|
||||
| `MAX_PROGRAM_INSTRUCTION_ACCOUNTS` | `255` |
|
||||
| `MAX_PROGRAM_INSTRUCTION_DATA_LEN` | `10_240` |
|
||||
|
||||
Ces valeurs sont des **bornes d'admission Interface**. Elles ne constituent pas une garantie qu'une instruction donnée tient dans toutes les contraintes d'une transaction Solana top-level. La limite CPI de comptes uniques n'est notamment pas transformée en règle artificielle sur la liste d'account metas.
|
||||
|
||||
Un dépassement utilise le code commun :
|
||||
|
||||
```text
|
||||
interface.program_instruction_limit_exceeded
|
||||
```
|
||||
|
||||
Le contexte d'erreur est limité aux métadonnées sûres `field`, `actual_len` et `maximum_len`. Aucun payload arbitraire ni account meta hostile n'est recopié dans l'erreur.
|
||||
|
||||
Le `Debug` de `ProgramInstruction` est volontairement borné : il affiche `program_id`, `account_count` et `data_len`, jamais les accounts complets ni les octets du payload.
|
||||
|
||||
## Codecs et runtime
|
||||
|
||||
La foundation `0.2.13` n'ajoute aucun codec par réflexe :
|
||||
|
||||
```text
|
||||
serde / serde_json absents
|
||||
borsh absent
|
||||
wincode absent
|
||||
bincode absent
|
||||
solana-instruction absent
|
||||
```
|
||||
|
||||
Des codecs/layouts/discriminants spécifiques pourront être ajoutés ultérieurement uniquement lorsqu'un vertical Program réel en démontre le besoin et que leur ownership wire appartient bien à Interface.
|
||||
|
||||
La crate ne produit aucun événement runtime. Elle ne dépend donc pas de `ksp-logging-lib` et ne possède ni `constants.rs` ni `TRACING_TARGET`. Si un futur comportement Interface exige réellement du logging, le runtime devra passer par la façade Logging KSP plutôt que par une dépendance directe à Tracing.
|
||||
|
||||
## Frontières
|
||||
|
||||
@@ -21,12 +111,21 @@ La façade crate-root expose actuellement le `Pubkey` canonique de Core. Les con
|
||||
|
||||
```text
|
||||
RPC / WebSocket / gRPC
|
||||
provider DTOs Transport
|
||||
wallet / signature
|
||||
persistence / Store
|
||||
Config / environnement
|
||||
interprétation métier Program
|
||||
execution policy
|
||||
persistence / Store
|
||||
Program decoding / recognition / proofs
|
||||
execution policy / signers
|
||||
transaction replay / CPI path / runtime logs
|
||||
lifecycle réseau
|
||||
```
|
||||
|
||||
La conception détaillée de la foundation est suivie dans [`../../docs/plans/020-V0_2_13_INTERFACE_PLAN.md`](../../docs/plans/020-V0_2_13_INTERFACE_PLAN.md) et sa validation dans [`../../docs/validation/016-V0_2_13_INTERFACE.md`](../../docs/validation/016-V0_2_13_INTERFACE.md).
|
||||
La foundation Program API est reportée à `0.2.14`. Les wires génériques d'acquisition/CORE restent reportés à `0.3.2+`.
|
||||
|
||||
## Références
|
||||
|
||||
- [Usage public](USAGE.md)
|
||||
- [Plan `0.2.13`](../../docs/plans/020-V0_2_13_INTERFACE_PLAN.md)
|
||||
- [Validation `0.2.13`](../../docs/validation/016-V0_2_13_INTERFACE.md)
|
||||
- [Architecture Wire + Program](../../docs/architecture/006-WIRE_AND_PROGRAM.md)
|
||||
|
||||
@@ -1,24 +1,122 @@
|
||||
<!-- file: crates/ksp-interface-lib/USAGE.md -->
|
||||
<!-- version: 1 -->
|
||||
<!-- version: 2 -->
|
||||
|
||||
# Usage de ksp-interface-lib
|
||||
|
||||
Cette page décrit la surface publique actuellement matérialisée par la foundation Interface. Les APIs d'instruction sont ajoutées progressivement sans exposer les modules internes.
|
||||
Cette page décrit la façade publique matérialisée par `0.2.13`. Les modules internes ne font pas partie du contrat consommable : utiliser uniquement les exports du crate-root.
|
||||
|
||||
## Utiliser le Pubkey canonique
|
||||
|
||||
Interface réexporte le `Pubkey` possédé par Core afin que les futurs contrats wire puissent partager la même primitive sans wrapper parallèle :
|
||||
## Construire des account metas
|
||||
|
||||
```rust
|
||||
let program_id = ksp_interface_lib::Pubkey::default();
|
||||
let bytes = program_id.to_bytes();
|
||||
assert_eq!(bytes.len(), 32);
|
||||
let readonly_account = ksp_interface_lib::Pubkey::new_from_array([1_u8; 32]);
|
||||
let writable_account = ksp_interface_lib::Pubkey::new_from_array([2_u8; 32]);
|
||||
|
||||
let readonly = ksp_interface_lib::ProgramAccountMeta::readonly(readonly_account, true);
|
||||
let writable = ksp_interface_lib::ProgramAccountMeta::writable(writable_account, false);
|
||||
|
||||
assert_eq!(readonly.pubkey(), &readonly_account);
|
||||
assert!(readonly.is_signer());
|
||||
assert!(!readonly.is_writable());
|
||||
|
||||
assert_eq!(writable.pubkey(), &writable_account);
|
||||
assert!(!writable.is_signer());
|
||||
assert!(writable.is_writable());
|
||||
```
|
||||
|
||||
Un consumer ne doit pas reconstruire une identité Program textuelle propre à Interface. Les Program IDs fondamentaux restent possédés et répertoriés par `ksp-core-lib`.
|
||||
`readonly`/`writable` décrivent uniquement les flags wire de l'account meta. Interface ne valide pas l'identité du compte contre un registry Program.
|
||||
|
||||
## Surface volontairement absente
|
||||
## Construire une instruction passive
|
||||
|
||||
La foundation initiale n'expose encore aucun constructeur d'instruction fonctionnel. Elle ne fournit pas non plus de codec générique Borsh/Wincode, de sérialisation Serde, de transport ou de comportement Program. Ces surfaces sont ajoutées uniquement lorsque leur contrat réel est matérialisé et borné.
|
||||
```rust
|
||||
let program_id = ksp_interface_lib::Pubkey::new_from_array([3_u8; 32]);
|
||||
let account_id = ksp_interface_lib::Pubkey::new_from_array([4_u8; 32]);
|
||||
|
||||
Aucun runtime logging n'est nécessaire pour les contrats passifs actuels ; une future instrumentation comportementale devrait passer par `ksp-logging-lib` selon les règles KSP au lieu d'introduire `tracing` directement.
|
||||
let account = ksp_interface_lib::ProgramAccountMeta::writable(account_id, true);
|
||||
let result = ksp_interface_lib::ProgramInstruction::try_new(
|
||||
program_id,
|
||||
std::vec![account, account],
|
||||
std::vec![7_u8, 8, 9],
|
||||
);
|
||||
|
||||
match result {
|
||||
std::result::Result::Ok(instruction) => {
|
||||
assert_eq!(instruction.program_id(), &program_id);
|
||||
assert_eq!(instruction.accounts(), &[account, account]);
|
||||
assert_eq!(instruction.data(), &[7_u8, 8, 9]);
|
||||
}
|
||||
std::result::Result::Err(error) => {
|
||||
eprintln!("{error}");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
L'ordre et les doublons des accounts sont conservés. Les octets `data` restent opaques : `ProgramInstruction` ne les sérialise, désérialise ni interprète.
|
||||
|
||||
Les `Vec` fournis à `try_new` sont consommés par la structure après validation des bornes ; aucun clone ou reformatage interne n'est requis par le contrat actuel.
|
||||
|
||||
## Bornes
|
||||
|
||||
Les limites publiques sont :
|
||||
|
||||
```rust
|
||||
assert_eq!(ksp_interface_lib::MAX_PROGRAM_INSTRUCTION_ACCOUNTS, 255);
|
||||
assert_eq!(ksp_interface_lib::MAX_PROGRAM_INSTRUCTION_DATA_LEN, 10_240);
|
||||
```
|
||||
|
||||
`255` account metas et `10_240` bytes de data sont admis. `256` account metas ou `10_241` bytes sont refusés par `try_new` avant création d'un `ProgramInstruction` valide.
|
||||
|
||||
Ces limites sont des bornes locales Interface et ne promettent pas qu'une instruction admise respecte à elle seule toutes les contraintes de taille/account-set d'une transaction Solana complète.
|
||||
|
||||
## Observer une erreur de limite
|
||||
|
||||
Le code public est :
|
||||
|
||||
```rust
|
||||
assert_eq!(
|
||||
ksp_interface_lib::ERROR_CODE_PROGRAM_INSTRUCTION_LIMIT_EXCEEDED.domain(),
|
||||
"interface",
|
||||
);
|
||||
assert_eq!(
|
||||
ksp_interface_lib::ERROR_CODE_PROGRAM_INSTRUCTION_LIMIT_EXCEEDED.code(),
|
||||
"program_instruction_limit_exceeded",
|
||||
);
|
||||
```
|
||||
|
||||
Une erreur de dépassement expose uniquement un contexte structurel sûr :
|
||||
|
||||
```text
|
||||
field
|
||||
actual_len
|
||||
maximum_len
|
||||
```
|
||||
|
||||
Le contenu du payload et les account metas arbitraires ne sont pas projetés dans le diagnostic.
|
||||
|
||||
## Debug borné
|
||||
|
||||
Le `Debug` de `ProgramInstruction` contient uniquement :
|
||||
|
||||
```text
|
||||
program_id
|
||||
account_count
|
||||
data_len
|
||||
```
|
||||
|
||||
Il ne faut donc pas attendre de ce rendu une sérialisation wire ou un dump du payload.
|
||||
|
||||
## Dépendances à ne pas ajouter côté consumer
|
||||
|
||||
Un consumer de la façade Interface n'a pas besoin d'ajouter un SDK Program Solana uniquement pour reconstruire `ProgramInstruction`. La crate utilise le `Pubkey` canonique partagé avec Core et conserve son propre contrat passif.
|
||||
|
||||
La foundation ne fournit volontairement pas :
|
||||
|
||||
```text
|
||||
serde générique
|
||||
Borsh / Wincode générique
|
||||
solana-instruction interop automatique
|
||||
transport réseau
|
||||
Program decoder/preparer
|
||||
signing/execution
|
||||
```
|
||||
|
||||
Ces surfaces doivent être introduites dans leur owner respectif lorsqu'un cas réel le justifie, pas comme dépendances implicites d'un consumer Interface.
|
||||
|
||||
Reference in New Issue
Block a user