Files
khadhroony-solana-project/crates/ksp-core-lib/USAGE.md
2026-08-23 11:15:57 +02:00

266 lines
7.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!-- file: crates/ksp-core-lib/USAGE.md -->
<!-- version: 1 -->
# Utilisation de `ksp-core-lib`
## Utiliser le type d'erreur commun
Une crate KSP définit des codes stables puis retourne `ksp_core_lib::Result<T>` :
```rust
const ERROR_CODE_LOAD_FAILED: ksp_core_lib::ErrorCode =
ksp_core_lib::ErrorCode::new("store", "load_failed");
fn load_value() -> ksp_core_lib::Result<u64> {
let error = ksp_core_lib::Error::new(
ERROR_CODE_LOAD_FAILED,
"unable to load value",
)
.with_context("operation", "load_value");
return std::result::Result::Err(error);
}
```
Le domaine et le code sont accessibles séparément :
```rust
let code = ERROR_CODE_LOAD_FAILED;
assert_eq!(code.domain(), "store");
assert_eq!(code.code(), "load_failed");
```
Le message et les champs de contexte restent accessibles sans parser `Display` :
```rust
let error = ksp_core_lib::Error::new(
ERROR_CODE_LOAD_FAILED,
"unable to load value",
)
.with_context("component", "postgres")
.with_context("operation", "load_value");
assert_eq!(error.code(), ERROR_CODE_LOAD_FAILED);
assert_eq!(error.message(), "unable to load value");
assert_eq!(error.context()[0].key(), "component");
assert_eq!(error.context()[0].value(), "postgres");
```
Un `ErrorContext` peut aussi être construit indépendamment lorsquun caller prépare explicitement son contexte :
```rust
let context = ksp_core_lib::ErrorContext::new(
"operation",
"load_value",
);
assert_eq!(context.key(), "operation");
assert_eq!(context.value(), "load_value");
```
Les valeurs de contexte doivent être sûres à exposer. Ne pas y placer de secret, credential, seed, key material, URL contenant une clé API ou payload brut volumineux.
## Conserver une erreur source
Une erreur externe compatible `Send + Sync + 'static` peut rester dans la chaîne standard :
```rust
#[derive(Debug)]
struct SourceError;
impl std::fmt::Display for SourceError {
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
return formatter.write_str("source failure");
}
}
impl std::error::Error for SourceError {}
let error = ksp_core_lib::Error::new(
ERROR_CODE_LOAD_FAILED,
"unable to load value",
)
.with_source(SourceError);
let source = std::error::Error::source(&error);
assert!(source.is_some());
```
La source sert au chaînage d'erreurs ; son contenu ne doit pas être recopié sans contrôle dans un contexte ou un log public.
## Utiliser `Pubkey`
Core réexporte la primitive Solana utilisée par les contrats KSP :
```rust
let system = ksp_core_lib::Pubkey::from_str_const(
ksp_core_lib::PRGID_SOLANA_SYSTEM,
);
assert_eq!(system, ksp_core_lib::PRGIDPK_SOLANA_SYSTEM);
```
Une crate consommatrice peut donc utiliser `ksp_core_lib::Pubkey` dans sa propre API sans dépendre directement de `solana-pubkey` lorsque Core est déjà le propriétaire architectural de cette primitive.
## Utiliser les constantes Program ID
Chaque Program ID Core possède une forme texte et une forme typée :
```rust
let system_text: &str = ksp_core_lib::PRGID_SOLANA_SYSTEM;
let system_pubkey: ksp_core_lib::Pubkey =
ksp_core_lib::PRGIDPK_SOLANA_SYSTEM;
assert_eq!(
system_pubkey,
ksp_core_lib::Pubkey::from_str_const(system_text),
);
```
Les constantes `PRGID_*` sont utiles pour les wires, diagnostics sûrs ou comparaisons texte. Les constantes `PRGIDPK_*` sont préférées dès qu'un contrat manipule une adresse Solana typée.
## Déclarer une paire texte / `Pubkey`
`declare_program_id!` permet à une couche KSP propriétaire d'un Program ID de déclarer les deux représentations depuis une seule valeur Base58 :
```rust
ksp_core_lib::declare_program_id!(
PRGID_EXAMPLE,
PRGIDPK_EXAMPLE,
"11111111111111111111111111111111"
);
assert_eq!(PRGID_EXAMPLE, ksp_core_lib::PRGID_SOLANA_SYSTEM);
assert_eq!(PRGIDPK_EXAMPLE, ksp_core_lib::PRGIDPK_SOLANA_SYSTEM);
```
La macro ne signifie pas que toute nouvelle constante doit être ajoutée au registre Core. La couche propriétaire du domaine décide où vit le nouveau Program ID.
## Parcourir le registre canonique
`entries()` retourne le registre complet en ordre déterministe :
```rust
for entry in ksp_core_lib::entries() {
let code = entry.code();
let name = entry.name();
let text = entry.program_id();
let pubkey = entry.pubkey();
let domain = entry.domain();
let family = entry.family();
let protocol = entry.protocol();
let subfamily = entry.subfamily();
let program_version = entry.program_version();
let kind = entry.kind();
let _ = (
code,
name,
text,
pubkey,
domain,
family,
protocol,
subfamily,
program_version,
kind,
);
}
```
`native_program_ids()` fournit la vue des Program IDs Solana fondamentaux actuellement enregistrés :
```rust
let count = ksp_core_lib::native_program_ids().count();
assert_eq!(count, 18);
```
## Rechercher une entrée
Recherche par représentation Base58 :
```rust
let entry = ksp_core_lib::find_program_id(
ksp_core_lib::PRGID_SOLANA_SYSTEM,
);
let entry = match entry {
std::option::Option::Some(value) => value,
std::option::Option::None => return,
};
assert_eq!(entry.code(), "solana.system");
```
Recherche par `Pubkey` :
```rust
let entry = ksp_core_lib::find_program_pubkey(
&ksp_core_lib::PRGIDPK_SOLANA_VOTE,
);
assert!(entry.is_some());
```
Une recherche inconnue retourne `None`; le registre n'invente pas une entrée générique.
## Filtrer par axe simple
Les helpers spécialisés conviennent aux filtres simples :
```rust
let loaders = ksp_core_lib::program_ids_by_family("loader");
for loader in loaders {
assert_eq!(loader.family(), "loader");
}
```
Les vues disponibles peuvent être consommées directement :
```rust
let solana_entries = ksp_core_lib::program_ids_by_domain("solana").count();
let loaders = ksp_core_lib::program_ids_by_family("loader").count();
let solana_protocol = ksp_core_lib::program_ids_by_protocol("solana").count();
assert_eq!(solana_entries, 18);
assert_eq!(loaders, 5);
assert_eq!(solana_protocol, 18);
```
## Combiner plusieurs axes
`ProgramIdFilter` compose les contraintes sans allocation de collection intermédiaire :
```rust
let filter = ksp_core_lib::ProgramIdFilter::new()
.with_domain("solana")
.with_family("loader")
.with_protocol("solana")
.with_subfamily("bpf")
.with_program_version("v2")
.with_kind(ksp_core_lib::ProgramIdKind::Loader);
for entry in ksp_core_lib::program_ids(filter) {
assert_eq!(entry.domain(), "solana");
assert_eq!(entry.family(), "loader");
assert_eq!(entry.protocol(), "solana");
assert_eq!(entry.subfamily(), std::option::Option::Some("bpf"));
assert_eq!(entry.program_version(), std::option::Option::Some("v2"));
assert_eq!(entry.kind(), ksp_core_lib::ProgramIdKind::Loader);
}
```
Un `ProgramIdFilter::new()` vide correspond à toutes les entrées du registre.
## Choisir entre texte, `Pubkey` et descriptor
Utiliser :
```text
PRGID_* / &str pour une représentation Base58 canonique
PRGIDPK_* / Pubkey pour un contrat Solana typé
ProgramIdEntry lorsqu'il faut aussi la taxonomie KSP
```
Ne pas reparcourir les constantes ou reconstruire une taxonomie parallèle dans une crate consommatrice lorsque le registre Core fournit déjà l'information requise.