275 lines
8.5 KiB
Markdown
275 lines
8.5 KiB
Markdown
<!-- file: kb-pipeline/USAGE.md -->
|
||
<!-- version: 4 -->
|
||
|
||
# Utilisation de kb-pipeline
|
||
|
||
## Objectif
|
||
|
||
La crate expose les campagnes bornées d’acquisition, d’extraction, de replay et les inspections stateful nécessaires aux applications et scénarios.
|
||
|
||
## Valider une requête d’extraction Core
|
||
|
||
```rust
|
||
fn validate_pending_extraction() -> kb_core::Result<()> {
|
||
let request = kb_pipeline::CoreExtractionRequest {
|
||
source: kb_pipeline::CoreExtractionSource::Pending,
|
||
limit: 1_000,
|
||
max_concurrent_extractions: 4,
|
||
force_replay: false,
|
||
};
|
||
|
||
request.validate()
|
||
}
|
||
```
|
||
|
||
Une extraction ciblée peut utiliser `CoreExtractionSource::Signatures`, `SlotRange` ou `ProgramId`.
|
||
|
||
## Exécuter une campagne d’extraction Core
|
||
|
||
```rust
|
||
async fn run_core_extraction<S, O>(
|
||
store: &S,
|
||
observer: &O,
|
||
request: kb_pipeline::CoreExtractionRequest,
|
||
) -> kb_core::Result<kb_pipeline::CoreExtractionSummary>
|
||
where
|
||
S: kb_store::CanonicalTransactionStore
|
||
+ kb_store::CoreExtractionStore
|
||
+ Sync,
|
||
O: kb_pipeline::CoreExtractionObserver,
|
||
{
|
||
let result = kb_pipeline::execute_core_extraction(store, observer, request).await;
|
||
|
||
match result {
|
||
Ok(summary) => Ok(summary),
|
||
Err(error) => Err(error),
|
||
}
|
||
}
|
||
```
|
||
|
||
## Préparer une requête de decode replay
|
||
|
||
```rust
|
||
fn validate_decode_request(
|
||
selection: kb_store::DecodeSelectionFilter,
|
||
) -> kb_core::Result<()> {
|
||
let request = kb_pipeline::DecodeReplayRequest {
|
||
campaign_id: "manual-replay-001".to_string(),
|
||
selection,
|
||
decoder_names: Vec::new(),
|
||
dispatch_policy: kb_pipeline::DecodeDispatchPolicy::HighestPriority,
|
||
max_concurrent_inputs: 4,
|
||
force_replay: false,
|
||
force_replay_all_matching: false,
|
||
materialize_after_decode: true,
|
||
};
|
||
|
||
request.validate()
|
||
}
|
||
```
|
||
|
||
Une liste vide dans `decoder_names` signifie que tous les décodeurs fournis à l’orchestrateur restent éligibles.
|
||
|
||
## Exécuter un decode replay
|
||
|
||
```rust
|
||
async fn run_decode_replay<S, O>(
|
||
store: &S,
|
||
observer: &O,
|
||
request: kb_pipeline::DecodeReplayRequest,
|
||
decoders: &[&dyn kb_lib::MdApiInstructionDecoder],
|
||
materializers: &[&dyn kb_lib::MdApiEventMaterializer],
|
||
) -> kb_core::Result<kb_pipeline::DecodeReplaySummary>
|
||
where
|
||
S: kb_store::DecodeReplayStore + Sync,
|
||
O: kb_pipeline::DecodeReplayObserver,
|
||
{
|
||
let result = kb_pipeline::execute_decode_replay(
|
||
store,
|
||
observer,
|
||
request,
|
||
decoders,
|
||
materializers,
|
||
)
|
||
.await;
|
||
|
||
match result {
|
||
Ok(summary) => Ok(summary),
|
||
Err(error) => Err(error),
|
||
}
|
||
}
|
||
```
|
||
|
||
## Backfill HTTP
|
||
|
||
La surface principale utilise `BackfillRequest`, `BackfillObserver`, `execute_http_backfill` et `BackfillSummary`.
|
||
|
||
```rust
|
||
async fn run_backfill<S, O>(
|
||
store: &S,
|
||
observer: &O,
|
||
request: kb_pipeline::BackfillRequest,
|
||
) -> kb_core::Result<kb_pipeline::BackfillSummary>
|
||
where
|
||
S: kb_store::CanonicalTransactionStore + Sync,
|
||
O: kb_pipeline::BackfillObserver,
|
||
{
|
||
let result = kb_pipeline::execute_http_backfill(store, observer, request).await;
|
||
|
||
match result {
|
||
Ok(summary) => Ok(summary),
|
||
Err(error) => Err(error),
|
||
}
|
||
}
|
||
```
|
||
|
||
## Inspections stateful
|
||
|
||
Les familles publiques comprennent :
|
||
|
||
- `inspect_solana_core_stateful_readiness` ;
|
||
- inspections SPL Token et ATA ;
|
||
- inspections et corrélations Token-2022 ;
|
||
- préflight cryptographique Token-2022 ;
|
||
- lecture et matérialisation stateful du registre ElGamal.
|
||
|
||
```rust
|
||
async fn inspect_classic_token<S>(
|
||
store: &S,
|
||
request: kb_pipeline::SplTokenStatefulReadinessRequest,
|
||
) -> kb_core::Result<kb_pipeline::SplTokenStatefulReadinessReport>
|
||
where
|
||
S: kb_store::CanonicalTransactionStore + Sync,
|
||
{
|
||
let result = kb_pipeline::inspect_spl_token_stateful_readiness(store, request).await;
|
||
|
||
match result {
|
||
Ok(report) => Ok(report),
|
||
Err(error) => Err(error),
|
||
}
|
||
}
|
||
```
|
||
|
||
Les rapports stateful ne constituent jamais une autorisation implicite d’exécution.
|
||
|
||
## Observateurs
|
||
|
||
Les campagnes longues exposent des traits d’observation distincts pour le backfill, l’extraction Core et le replay. L’observateur peut publier la progression et participer à l’annulation coopérative selon le contrat concerné.
|
||
|
||
## Erreurs et invariants
|
||
|
||
- toutes les campagnes sont bornées ;
|
||
- la progression persistée ne doit avancer qu’après traitement cohérent ;
|
||
- le replay doit rester déterministe pour une même entrée et une même version de pipeline ;
|
||
- une matérialisation ne doit pas inventer un état confirmé ;
|
||
- les erreurs de transport, stockage, décodage et préflight restent distinguées.
|
||
|
||
## Tests de référence
|
||
|
||
- tests de frontière contiguë et reprise du backfill ;
|
||
- tests d’extraction Core et d’idempotence ;
|
||
- tests de decode replay, dispatch et matérialisation ;
|
||
- tests stateful SPL Token, ATA et Token-2022 ;
|
||
- tests de preuves, préflight cryptographique et postconditions ;
|
||
- tests du registre ElGamal fail-closed.
|
||
|
||
## Limites durables
|
||
|
||
- la crate orchestre les traitements mais ne fournit pas d’interface opérateur ;
|
||
- elle ne conserve pas de secret de wallet ;
|
||
- elle ne remplace pas les scénarios Devnet et validations explicites de `kb-pipeline-demo-scenarios`.
|
||
|
||
## Lire un compte Metaplex Token Metadata
|
||
|
||
La lecture stateful exige un endpoint HTTP, une catégorie de compte explicite et une borne stricte sur les données décodées.
|
||
|
||
```rust
|
||
async fn read_metaplex_metadata(
|
||
pool: &kb_onchain_transport::HttpEndpointPool,
|
||
metadata: kb_lib::MdPubkey,
|
||
) -> kb_core::Result<kb_pipeline::MetaplexTokenMetadataStatefulReadResult> {
|
||
let request = kb_pipeline::MetaplexTokenMetadataStatefulReadRequest {
|
||
query_role: "rpc".to_string(),
|
||
account: metadata,
|
||
kind: kb_pipeline::MetaplexTokenMetadataAccountKind::Metadata,
|
||
min_context_slot: std::option::Option::None,
|
||
max_data_bytes: kb_pipeline::MAX_METAPLEX_TOKEN_METADATA_ACCOUNT_BYTES,
|
||
};
|
||
let result = kb_pipeline::read_metaplex_token_metadata_stateful_snapshot(
|
||
pool,
|
||
&request,
|
||
)
|
||
.await;
|
||
|
||
match result {
|
||
Ok(snapshot) => Ok(snapshot),
|
||
Err(error) => Err(error),
|
||
}
|
||
}
|
||
```
|
||
|
||
Pour une edition, fournir le mint dans `MetaplexTokenMetadataAccountKind::Edition`. Pour un token record programmable, fournir le mint et le token account dans `TokenRecord`.
|
||
|
||
## Inspecter le préflight Metaplex
|
||
|
||
Le préflight lie un plan préparé par `kb-lib` à des snapshots confirmés et applique la politique des opérations dépréciées.
|
||
|
||
```rust
|
||
fn inspect_metaplex_preflight(
|
||
plan: kb_lib::ExApiPreparedExecutionPlan,
|
||
snapshots: Vec<kb_pipeline::MetaplexTokenMetadataStatefulReadResult>,
|
||
allow_deprecated_operation: bool,
|
||
) -> kb_core::Result<kb_pipeline::MetaplexTokenMetadataPreflightReport> {
|
||
let request = kb_pipeline::MetaplexTokenMetadataPreflightRequest {
|
||
plan,
|
||
snapshots,
|
||
allow_deprecated_operation,
|
||
};
|
||
|
||
kb_pipeline::inspect_metaplex_token_metadata_preflight(&request)
|
||
}
|
||
```
|
||
|
||
Une opération marquée dépréciée par `kb-lib` est refusée lorsque `allow_deprecated_operation` vaut `false`.
|
||
|
||
## Valider l’enveloppe d’exécution Metaplex
|
||
|
||
L’orchestration refuse la signature ou la soumission tant que la simulation exacte du message, les signers et la confirmation opérateur ne sont pas cohérents.
|
||
|
||
```rust
|
||
fn validate_metaplex_execution(
|
||
plan: kb_lib::ExApiPreparedExecutionPlan,
|
||
preflight: kb_pipeline::MetaplexTokenMetadataPreflightReport,
|
||
message_hash: String,
|
||
resolved_signers: Vec<kb_lib::MdPubkey>,
|
||
) -> kb_core::Result<kb_pipeline::MetaplexTokenMetadataExecutionReadinessReport> {
|
||
let request = kb_pipeline::MetaplexTokenMetadataExecutionReadinessRequest {
|
||
plan,
|
||
preflight,
|
||
message_hash: message_hash.clone(),
|
||
simulated_message_hash: message_hash,
|
||
simulated: true,
|
||
simulation_succeeded: true,
|
||
resolved_signers,
|
||
submit: false,
|
||
operator_confirmed: false,
|
||
};
|
||
|
||
kb_pipeline::validate_metaplex_token_metadata_execution_readiness(&request)
|
||
}
|
||
```
|
||
|
||
Pour une soumission réelle, `submit` et `operator_confirmed` doivent être vrais et le plan ne doit plus être en `dry_run`.
|
||
|
||
## Agréger les postconditions Metaplex
|
||
|
||
```rust
|
||
fn summarize_metaplex_postconditions(
|
||
statuses: &[kb_pipeline::MetaplexTokenMetadataPostconditionStatus],
|
||
) -> kb_pipeline::MetaplexTokenMetadataPostconditionStatus {
|
||
kb_pipeline::summarize_metaplex_token_metadata_postconditions(statuses)
|
||
}
|
||
```
|
||
|
||
`Contradicted` est prioritaire sur `Confirmed`, et l’absence de postcondition applicable reste `NotApplicable`.
|