Files
khadhroony-solana-project/docs/architecture/008-DATA_MATERIALIZATION_AND_STORE.md
2026-09-04 09:58:20 +02:00

409 lines
12 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: docs/architecture/008-DATA_MATERIALIZATION_AND_STORE.md -->
<!-- version: 6 -->
# Data, Materialization et Store
## Objet
Ce document définit la chaîne durable KSP, la responsabilité du Store et les frontières de replay.
La nomenclature canonique est désormais :
```text
RAW -> CORE -> DECODE -> SPECIALIZED
```
Les aliases D1D4 restent utilisés pour les niveaux persistés :
```text
D1 = RAW
D2 = CORE
D3 = DECODE / matérialisation générique décodée
D4 = SPECIALIZED
```
Cette clarification remplace l'ancienne interprétation où D1 -> D2 pouvait déjà dépendre de `ksp-program-api`. **RAW et CORE sont indépendants de tout decoder Program.**
## Principes structurants
- le Store persiste des contrats de données ; il ne possède ni transport, ni decoder, ni materializer ;
- chaque frontière durable peut être rejouée indépendamment ;
- les données de provenance/versioning permettent de savoir quel processor a produit quel output ;
- les couches dérivées ne rendent jamais obligatoire une nouvelle acquisition réseau lorsque l'input durable nécessaire existe déjà ;
- D4 privilégie les faits métier génériques lorsqu'une normalisation inter-protocoles est pertinente.
## D1 — RAW
### Mission
RAW conserve l'acquisition suffisamment fidèlement pour reconstruire CORE sans redemander la donnée au provider lorsqu'elle a déjà été capturée.
Le transport peut normaliser plusieurs providers vers un modèle KSP homogène, mais D1 doit rester lossless pour les besoins de replay couverts.
D1 ne décode aucun programme Solana/SPL/Metaplex/DEX.
### Frontière Transport -> RAW
```text
HTTP / WS / gRPC / provider
|
v
ksp-onchain-transport-lib
|
v
conversion explicite
|
v
ksp-store-api RAW DTO
|
v
ksp-store-lib
```
`ksp-onchain-transport-lib` ne dépend ni de `ksp-store-api` ni de `ksp-store-lib`.
### Provenance RAW
Selon la catégorie, D1 doit pouvoir conserver notamment :
- cluster/network ;
- slot/signature/pubkey/identité blockchain applicable ;
- payload replayable ;
- provider ;
- endpoint/source/transport ;
- rôle d'acquisition : live, backfill, import ;
- instant d'observation ;
- instant de persistence ;
- identité/hash d'idempotence ;
- cursor/page/range/checkpoint lorsque pertinent.
## D2 — CORE
### Mission
CORE est une **normalisation canonique générique de la blockchain Solana**.
Cette couche doit fonctionner même si `ksp-program-api` et `ksp-program-lib` ne sont pas encore capables de décoder le moindre programme métier.
Exemples de faits CORE candidats :
- slots ;
- blocks et block metadata ;
- signatures ;
- transactions ;
- messages legacy/versioned ;
- account keys et address lookups ;
- comptes et états bruts structurés génériquement ;
- instructions top-level brutes ;
- instructions CPI brutes ;
- logs ;
- transaction meta ;
- balances/fees/rewards lorsqu'ils appartiennent au contrat blockchain générique ;
- return data brute ;
- relations structurelles transaction/message/instruction/account.
Un fait CORE peut contenir un `program_id`, des bytes et des indexes sans savoir que l'instruction représente un `Transfer`, un `Swap` ou une mutation Metadata.
### Frontière RAW -> CORE
```text
D1 RAW
|
v
normalisation Solana générique
|
v
D2 CORE
```
Interdictions :
```text
RAW -> CORE -X-> ksp-program-api
RAW -> CORE -X-> ksp-program-lib
RAW -> CORE -X-> ksp-materializer-api
```
Les codecs/wires génériques nécessaires à la structure Solana peuvent provenir de `ksp-interface-lib` lorsqu'ils appartiennent à la façade wire officielle, sans transformer cette étape en décodage Program.
### Provenance CORE
D2 doit pouvoir relier chaque résultat à :
- son input D1 ;
- l'identité/version du normalizer CORE ;
- un hash logique d'input ;
- l'instant de processing/persistence ;
- son état de processing durable lorsque nécessaire.
## D3 — DECODE / matérialisation générique
### Mission
DECODE commence lorsque KSP interprète un `program_id`, un layout d'instruction, un compte ou un événement selon un contrat Program/protocole.
La progression logique d'un groupe est :
```text
CORE
|
v
decoder Program
|
v
decoded facts
|
v
materialisation générique / journal durable
|
v
D3 DECODE
```
D3 conserve l'équivalent conceptuel obligatoire du journal générique de matérialisation de bot3 (`k_sol_mat_outputs`), sans imposer son ancien schéma ou son nom physique.
Le journal doit pouvoir répondre au minimum :
```text
quel input CORE ?
quel program/decoder ?
quelle version ?
quel materializer ?
quelle version ?
quel output logique ?
quel type/domaine ?
quel hash ?
quel instant ?
quel état/superseded/failed/replay ?
```
Les types exacts de decoded facts et du journal sont décidés lorsque les premiers vertical slices Program existent.
### Frontière CORE -> DECODE
```text
D2 CORE
|
v
ksp-program-api implementation
|
v
decoded output
|
v
ksp-materializer-api implementation
|
v
D3 journal / decoded materialization
```
Les implémentations officielles pourront provenir de `ksp-program-lib` et `ksp-materializer-lib`; des implémentations externes compatibles restent possibles.
Program et Materializer ne dépendent pas du backend Store.
## D4 — SPECIALIZED
### Mission
SPECIALIZED expose des projections queryables utiles aux applications, analyses et futurs modèles ML.
Exemples :
- token/asset state ;
- metadata canonique d'asset ;
- pools/markets ;
- reserves/liquidity ;
- positions ;
- swaps/trades ;
- fees ;
- observations de prix ;
- OHLC/candles ;
- routes et legs ;
- faits trading-adjacent ;
- projections d'autres domaines futurs.
### Faits métier génériques
Les projections de trading ne sont pas séparées automatiquement par protocole.
Préférer lorsque possible :
```text
liquidity_pools
trades
positions
price_observations
ohlc
routes
route_legs
```
plutôt que :
```text
meteora_trades
raydium_trades
orca_trades
pump_trades
```
Les champs réellement protocol-specific peuvent être conservés dans une extension ou une projection dédiée uniquement lorsqu'un besoin de requête/invariant le justifie.
### Metadata
La direction reste :
- projection canonique commune pour metadata d'assets/tokens alimentée par Metaplex Token Metadata et Token-2022 Metadata ;
- SPM reste distinct et sera redéveloppé plus tard avec le décodage généraliste.
### OHLC
Les candles sont des projections SPECIALIZED calculées à partir des trades/price observations persistés.
Une application marché lit les OHLC matérialisés ; elle ne reparcourt pas toutes les transactions pour reconstruire les candles à chaque affichage.
## Vertical slices Program
RAW et CORE sont développés horizontalement.
À partir de DECODE, la progression est verticale par groupe :
```text
wire
-> decode
-> generic materialization / D3
-> specialized projection / D4 si utile
-> execution preparation
-> execution policy
-> execution
-> Devnet scenarios / validation
```
Un groupe doit atteindre une cohérence verticale suffisante avant que le groupe suivant devienne prioritaire.
Les composants satellites nécessaires à un protocole appartiennent à son groupe : Pump fees avec Pump, Meteora vaults avec Meteora, etc.
## `ksp-store-api`
`ksp-store-api` est backend-agnostic et porte les contrats nécessaires aux consommateurs.
La première implementation `0.3.1` est volontairement **RAW-only** : elle ne crée pas prématurément les contrats physiques D2/D3/D4.
Les surfaces CORE/DECODE/SPECIALIZED sont ajoutées quand leurs couches sont réellement ouvertes.
## `ksp-store-lib` et backends physiques
`ksp-store-lib` est la façade/runtime Store commune derrière `ksp-store-api`. Il sélectionne uniquement les backends compilés par ses features, convertit ses settings KSP-owned vers le backend retenu, expose le lifecycle commun et masque les objets physiques du moteur.
Il possède notamment :
- identité et sélection de backend côté façade ;
- settings Store publics KSP-owned indépendants de Config ;
- lifecycle commun `open` / `close` ;
- dispatch vers le backend compilé ;
- mapping des diagnostics/health backend vers une projection portable lorsque cette surface est justifiée ;
- réexport de la surface `ksp-store-api` utile aux consumers.
Le backend PostgreSQL officiel appartient à `ksp-store-postgres-lib`. Cette crate dépend de `ksp-store-api`, ne dépend jamais de `ksp-store-lib` et possède seule :
- `tokio-postgres` et le pool PostgreSQL ;
- le connecteur TLS PostgreSQL ;
- SQL et statements physiques ;
- transactions PostgreSQL ;
- migrations/bootstrap et metadata de schéma ;
- mapping rows/backend ;
- détails de cursorisation physique ;
- diagnostics PostgreSQL internes.
`ksp-store-lib` et les crates backend ne possèdent pas :
- transport réseau dacquisition ;
- decoder Program ;
- materializer ;
- orchestration de worker/job ;
- politique de batch, backlog, priorité ou retry de processing.
La pagination/cursorisation reste un contrat de navigation Store. Une limite demandée par lappelant peut être validée pour sa forme/sécurité, mais aucun plafond métier global arbitraire ni batch-size de worker nest introduit par le runtime Store.
### Navigation machine et inspection humaine
Deux contrats complémentaires coexistent sans collision :
```text
workers / jobs / replay -> RawPageRequest + RawPageCursor -> keyset
inspection UI -> RawInspectionPageRequest -> offset + limit + counts exacts
```
La voie cursor/keyset reste canonique pour la navigation machine et les replays : le cursor est opaque, lié au contexte de query et ne dépend pas d'un `OFFSET` profond.
La voie `RawInspectionPageRequest` est backend-neutral mais conçue pour une inspection humaine random-access. Elle peut demander des counts exacts et un offset absolu ; le backend PostgreSQL peut implémenter cette capability avec `COUNT` et `OFFSET` privés. Ce choix ne réécrit jamais les statements keyset historiques.
`ksp-app-store-desk` est le consumer actuel de cette voie d'inspection. DataTables possède l'unique pager visible et l'application ne reçoit aucun cursor Store. Les summaries d'inspection restent sans payload/data RAW ; un détail explicite peut recharger une seule entité avec une projection applicative bornée.
## `ksp-materializer-api` et `ksp-materializer-lib`
Ils sont introduits seulement lorsque le premier groupe DECODE démontre le contrat réel.
`ksp-materializer-api` porte les contrats extensibles ; `ksp-materializer-lib` contient les implementations officielles communes.
Une projection très locale/spécifique peut rester dans son groupe si la création d'une implémentation commune séparée n'apporte pas de réutilisation réelle.
## Replay
Les frontières durables restent replayables indépendamment :
```text
RAW -> CORE
CORE -> DECODE
DECODE -> SPECIALIZED
```
Un replay d'une couche dérivée ne doit pas refaire arbitrairement les couches précédentes.
## Notifications persistées
Le Store reste source de vérité du backlog.
Les notifications ne sont qu'un wake-up : elles peuvent être perdues ou dupliquées.
Ordre :
```text
persist
commit
notify
```
Le consumer reconstruit toujours son backlog depuis le Store avec les versions de processor et les marqueurs d'idempotence.
## Acquisition live et backfill
Live et backfill alimentent la même frontière RAW :
```text
live worker ----\
+--> RAW persistence
backfill job ----/
```
Ils ne dupliquent pas le contrat durable.
## Stabilité
La stabilité cible est différente selon la couche :
- RAW : fortement stable après mise en production ;
- CORE : fortement stable après validation de la normalisation Solana générique ;
- DECODE : extensible par nouveaux Program/versions ;
- SPECIALIZED : plus évolutif selon les besoins de query, trading et analytics.
## Questions laissées ouvertes
- schémas SQL exacts RAW puis CORE ;
- représentation persistable exacte d'un decoded output ;
- contrat exact du journal D3 ;
- granularité des projectors SPECIALIZED ;
- politique de supersession/versioning des outputs ;
- fenêtres OHLC initiales ;
- mécanisme de contexte pour les projections stateful.