v0.2.14-pre.004
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
<!-- file: crates/ksp-program-api/USAGE.md -->
|
||||
<!-- version: 2 -->
|
||||
<!-- version: 3 -->
|
||||
|
||||
# Usage de ksp-program-api
|
||||
|
||||
Cette page décrit la surface publique disponible à partir de `0.2.14-pre.003`. Utiliser uniquement les exports du crate-root ; aucun module interne ne fait partie du contrat consommable.
|
||||
Cette page décrit la surface publique disponible à partir de `0.2.14-pre.004`. Utiliser uniquement les exports du crate-root ; aucun module interne ne fait partie du contrat consommable.
|
||||
|
||||
## Construire un input Program avec la façade
|
||||
|
||||
@@ -21,12 +21,70 @@ let instruction = ksp_program_api::ProgramInstruction::try_new(
|
||||
assert!(instruction.is_ok());
|
||||
```
|
||||
|
||||
`Pubkey`, `ProgramAccountMeta` et `ProgramInstruction` conservent leur ownership Core/Interface. Program API fournit seulement une façade cohérente aux futures implémentations de capability Program.
|
||||
`Pubkey`, `ProgramAccountMeta` et `ProgramInstruction` conservent leur ownership Core/Interface.
|
||||
|
||||
## Représenter une reconnaissance
|
||||
## Implémenter un decoder externe
|
||||
|
||||
Le type décodé reste entièrement possédé par la crate d'implémentation :
|
||||
|
||||
```rust
|
||||
let recognition = ksp_program_api::ProgramInstructionRecognition::ProgramMatch;
|
||||
struct ExternalDecodedInstruction {
|
||||
opcode: u8,
|
||||
}
|
||||
|
||||
struct ExternalDecoder {
|
||||
program_ids: [ksp_program_api::Pubkey; 1],
|
||||
}
|
||||
|
||||
impl ksp_program_api::ProgramInstructionDecoder for ExternalDecoder {
|
||||
type Decoded = ExternalDecodedInstruction;
|
||||
|
||||
fn program_ids(&self) -> &[ksp_program_api::Pubkey] {
|
||||
return &self.program_ids;
|
||||
}
|
||||
|
||||
fn recognize(
|
||||
&self,
|
||||
instruction: &ksp_program_api::ProgramInstruction,
|
||||
) -> ksp_program_api::ProgramInstructionRecognition {
|
||||
if instruction.program_id() != &self.program_ids[0] {
|
||||
return ksp_program_api::ProgramInstructionRecognition::NoMatch;
|
||||
}
|
||||
return ksp_program_api::ProgramInstructionRecognition::ProgramMatch;
|
||||
}
|
||||
|
||||
fn decode(
|
||||
&self,
|
||||
instruction: &ksp_program_api::ProgramInstruction,
|
||||
) -> ksp_program_api::Result<ksp_program_api::ProgramInstructionDecodeOutcome<Self::Decoded>> {
|
||||
let opcode = match instruction.data().first() {
|
||||
std::option::Option::Some(value) => *value,
|
||||
std::option::Option::None => {
|
||||
return std::result::Result::Ok(
|
||||
ksp_program_api::ProgramInstructionDecodeOutcome::Unsupported,
|
||||
);
|
||||
}
|
||||
};
|
||||
return std::result::Result::Ok(
|
||||
ksp_program_api::ProgramInstructionDecodeOutcome::Decoded(
|
||||
ExternalDecodedInstruction { opcode },
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Aucun `ksp-program-lib`, enum centrale, `Any`, JSON ou codec n'est nécessaire. Le Program ID peut être un `Pubkey` opaque non enregistré par Core.
|
||||
|
||||
## Sélection explicite
|
||||
|
||||
La sélection reste distincte du décodage :
|
||||
|
||||
```rust
|
||||
let recognition = ksp_program_api::ProgramInstructionDecoder::recognize(
|
||||
&decoder,
|
||||
&instruction,
|
||||
);
|
||||
|
||||
match recognition {
|
||||
ksp_program_api::ProgramInstructionRecognition::NoMatch => {}
|
||||
@@ -36,35 +94,30 @@ match recognition {
|
||||
}
|
||||
```
|
||||
|
||||
Le wildcard est volontaire : l'enum est `#[non_exhaustive]` afin de ne pas transformer la foundation en vocabulaire fermé pour toujours.
|
||||
L'enum est `#[non_exhaustive]`. `decode` n'est pas un substitut à `recognize` : il traite une instruction déjà sélectionnée pour le decoder.
|
||||
|
||||
## Représenter un outcome de décodage
|
||||
|
||||
Le type décodé reste possédé par l'implémentation :
|
||||
## Outcome et erreur
|
||||
|
||||
```rust
|
||||
struct ExternalDecodedInstruction {
|
||||
opcode: u8,
|
||||
}
|
||||
|
||||
let outcome = ksp_program_api::ProgramInstructionDecodeOutcome::Decoded(
|
||||
ExternalDecodedInstruction { opcode: 7_u8 },
|
||||
);
|
||||
let outcome = ksp_program_api::ProgramInstructionDecoder::decode(
|
||||
&decoder,
|
||||
&instruction,
|
||||
)?;
|
||||
|
||||
match outcome {
|
||||
ksp_program_api::ProgramInstructionDecodeOutcome::Decoded(value) => {
|
||||
assert_eq!(value.opcode, 7_u8);
|
||||
let _opcode = value.opcode;
|
||||
}
|
||||
ksp_program_api::ProgramInstructionDecodeOutcome::Unsupported => {}
|
||||
_ => {}
|
||||
}
|
||||
```
|
||||
|
||||
Aucun `Any`, JSON ou enum centrale n'est nécessaire pour transporter ce type.
|
||||
Une erreur réelle est un `Err(ksp_program_api::Error)`. `Unsupported` n'est pas une deuxième forme d'erreur : il indique qu'une instruction reconnue n'est volontairement pas décodée par cette capability.
|
||||
|
||||
## Debug sûr
|
||||
|
||||
`ProgramInstructionDecodeOutcome<Decoded>` possède un `Debug` volontairement opaque sur la valeur décodée :
|
||||
`ProgramInstructionDecodeOutcome<Decoded>` possède un `Debug` volontairement opaque :
|
||||
|
||||
```rust
|
||||
struct SecretDecoded;
|
||||
@@ -73,34 +126,22 @@ let outcome = ksp_program_api::ProgramInstructionDecodeOutcome::Decoded(SecretDe
|
||||
assert_eq!(std::format!("{outcome:?}"), "Decoded");
|
||||
```
|
||||
|
||||
`SecretDecoded` n'a même pas besoin d'implémenter `Debug`. Cela empêche un diagnostic générique de rendre accidentellement un payload externe.
|
||||
`SecretDecoded` n'a pas besoin d'implémenter `Debug` et sa valeur n'est jamais rendue par l'outcome.
|
||||
|
||||
## Utiliser le contrat d'erreur commun
|
||||
## Hors surface `pre.004`
|
||||
|
||||
Les types d'erreur Core restent disponibles depuis la façade :
|
||||
|
||||
```rust
|
||||
fn forward_result(
|
||||
value: ksp_program_api::Result<ksp_program_api::ProgramInstruction>,
|
||||
) -> ksp_program_api::Result<ksp_program_api::ProgramInstruction> {
|
||||
return value;
|
||||
}
|
||||
```
|
||||
|
||||
Le futur `decode(...)` utilisera ce `Result`. Une erreur sera donc `Err(...)`, tandis que `Unsupported` signifie une instruction connue volontairement non prise en charge.
|
||||
|
||||
## Ce que `pre.003` ne fournit pas
|
||||
|
||||
Il n'existe encore aucun :
|
||||
Il n'existe toujours aucun :
|
||||
|
||||
```text
|
||||
ProgramInstructionDecoder
|
||||
program_ids(...)
|
||||
recognize(...) sur un trait
|
||||
decode(...) sur un trait
|
||||
registry de decoders
|
||||
payload générique JSON/Any
|
||||
execution preparer
|
||||
composition dyn hétérogène
|
||||
identity/version/coverage descriptor
|
||||
payload canonique D3
|
||||
ProgramAccountDecoder / Event / ReturnData
|
||||
ProgramExecutionPreparer
|
||||
execution policy
|
||||
serde / JSON / codec
|
||||
logging / runtime réseau
|
||||
```
|
||||
|
||||
Ces éléments ne doivent pas être simulés côté consumer. Le trait decoder et la preuve d'implémentation externe sont réservés à `pre.004`.
|
||||
Ces surfaces ne doivent pas être simulées côté consumer. Elles attendent les vertical slices qui justifieront leurs contrats réels.
|
||||
|
||||
Reference in New Issue
Block a user