200 lines
6.4 KiB
Markdown
200 lines
6.4 KiB
Markdown
<!-- file: crates/ksp-interface-lib/USAGE.md -->
|
|
<!-- version: 3 -->
|
|
|
|
# Usage de ksp-interface-lib
|
|
|
|
Cette page décrit l'utilisation durable de la façade publique. Les modules internes ne font pas partie du contrat consommable : utiliser uniquement les exports du crate-root.
|
|
|
|
## Construire des account metas
|
|
|
|
```rust
|
|
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());
|
|
```
|
|
|
|
`readonly`/`writable` décrivent uniquement les flags wire de l'account meta. Interface ne valide pas l'identité du compte contre un registry Program.
|
|
|
|
## Construire une instruction passive
|
|
|
|
```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]);
|
|
|
|
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.
|
|
|
|
## Respecter les bornes Program
|
|
|
|
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 `ProgramInstruction::try_new`.
|
|
|
|
Ces limites sont locales à Interface et ne promettent pas qu'une instruction admise respecte à elle seule toutes les contraintes 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.
|
|
|
|
## Construire un événement de lifecycle de slot
|
|
|
|
Un producer/composer qui a déjà établi la correspondance sémantique avec son DTO Transport peut construire le fait passif partagé :
|
|
|
|
```rust
|
|
let event = ksp_interface_lib::SlotLifecycleEvent::new(
|
|
42,
|
|
ksp_interface_lib::SlotLifecycleStage::Processed,
|
|
);
|
|
|
|
assert_eq!(event.slot(), 42);
|
|
assert_eq!(event.stage(), ksp_interface_lib::SlotLifecycleStage::Processed);
|
|
```
|
|
|
|
Les stages actuellement disponibles sont :
|
|
|
|
```text
|
|
Processed
|
|
FirstShredReceived
|
|
Completed
|
|
CreatedBank
|
|
Dead
|
|
OptimisticallyConfirmed
|
|
Rooted
|
|
```
|
|
|
|
Un consumer externe doit traiter `SlotLifecycleStage` comme une enum évolutive `#[non_exhaustive]` et prévoir un fallback dans ses `match`.
|
|
|
|
Le type ne contient volontairement ni timestamp, ni parent, ni diagnostic, ni source/provider, ni identifiant de subscription.
|
|
|
|
## Construire un événement d'exécution de transaction
|
|
|
|
Une signature doit d'abord être disponible sous sa forme canonique de 64 bytes :
|
|
|
|
```rust
|
|
let signature = ksp_interface_lib::TransactionSignature::new([7_u8; 64]);
|
|
|
|
let event = ksp_interface_lib::TransactionExecutionEvent::new(
|
|
123,
|
|
signature,
|
|
ksp_interface_lib::TransactionExecutionOutcome::Succeeded,
|
|
);
|
|
|
|
assert_eq!(event.slot(), 123);
|
|
assert_eq!(event.signature().as_bytes(), &[7_u8; 64]);
|
|
assert_eq!(
|
|
event.outcome(),
|
|
ksp_interface_lib::TransactionExecutionOutcome::Succeeded,
|
|
);
|
|
```
|
|
|
|
`TransactionExecutionOutcome` distingue uniquement `Succeeded` et `Failed` et reste `#[non_exhaustive]`.
|
|
|
|
Le `Debug` de `TransactionSignature` et de `TransactionExecutionEvent` n'affiche pas les bytes de signature.
|
|
|
|
## Convertir depuis Transport
|
|
|
|
Ne pas ajouter `ksp-onchain-transport-lib` comme dépendance de `ksp-interface-lib` pour fournir des `From<TransportDto>`.
|
|
|
|
La conversion appartient au composant qui connaît les deux côtés :
|
|
|
|
```text
|
|
Transport DTO riche
|
|
|
|
|
| conversion explicite dans composition/consumer
|
|
v
|
|
Interface event passif minimal
|
|
```
|
|
|
|
Ne construire un événement Interface que si la source fournit suffisamment d'information pour le fait commun exact. Si l'état est ambigu, conserver le DTO dans son owner Transport ou déclencher une hydratation adaptée ; ne pas inventer de valeur par défaut.
|
|
|
|
## Ne pas utiliser les événements comme stockage durable
|
|
|
|
`SlotLifecycleEvent` et `TransactionExecutionEvent` sont des faits passifs, pas des modèles RAW replayables.
|
|
|
|
Ils ne remplacent pas :
|
|
|
|
```text
|
|
RawTransaction
|
|
RawTransactionObservation
|
|
RawAccountState
|
|
RawAccountObservation
|
|
Store backlog / cursor / retention
|
|
```
|
|
|
|
Les consumers qui ont besoin de reprise après crash ou de replay doivent s'appuyer sur `ksp-store-lib`/`ksp-store-api` selon leur responsabilité, pas sur un event Interface en mémoire.
|
|
|
|
## 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`, ni un runtime Transport pour manipuler les événements passifs déjà normalisés.
|
|
|
|
La crate ne fournit volontairement pas :
|
|
|
|
```text
|
|
serde générique
|
|
Borsh / Wincode générique
|
|
solana-instruction interop automatique
|
|
transport réseau
|
|
converters provider automatiques
|
|
Program decoder/preparer
|
|
signing/execution
|
|
persistence/event bus
|
|
```
|
|
|
|
Ces surfaces doivent être introduites dans leur owner respectif lorsqu'un cas réel le justifie.
|