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

12 KiB
Raw Blame History

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 :

RAW -> CORE -> DECODE -> SPECIALIZED

Les aliases D1D4 restent utilisés pour les niveaux persistés :

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

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

D1 RAW
   |
   v
normalisation Solana générique
   |
   v
D2 CORE

Interdictions :

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 :

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 :

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

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 :

liquidity_pools
trades
positions
price_observations
ohlc
routes
route_legs

plutôt que :

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 :

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 :

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 :

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 :

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 :

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.