v0.3.4-pre.012
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
<!-- file: crates/ksp-store-lib/README.md -->
|
||||
<!-- version: 4 -->
|
||||
<!-- version: 5 -->
|
||||
|
||||
# ksp-store-lib
|
||||
|
||||
@@ -19,7 +19,7 @@ Elle expose aux consumers une surface backend-neutral, réexporte les contrats R
|
||||
- `Store::health().await` pour la readiness portable et bornée ;
|
||||
- `Store::close(self).await` pour la fermeture explicite bornée ;
|
||||
- le mapping des erreurs backend vers des codes Store stables sans exposer les erreurs physiques ;
|
||||
- les six capabilities `RawTransaction*` dispatchées vers le backend compilé ;
|
||||
- les dix capabilities RAW de `ksp-store-api` dispatchées vers le backend compilé : six `RawTransaction*` et quatre `RawAccount*` ;
|
||||
- une validation réseau backend-neutral avant dispatch pour toutes les opérations qui portent explicitement un réseau ;
|
||||
- les réexports crate-root de `ksp-store-api` nécessaires aux consumers ordinaires.
|
||||
|
||||
@@ -63,9 +63,9 @@ Store ne lit ni `.env`, ni variables `KSP_*` / `KSPB_*`, ni variables/fichiers i
|
||||
|
||||
`ksp-config-lib` possède `std.store`, la résolution des secrets et la sélection du target. Il construit ensuite un `StoreSettings` backend-neutral. L'URI PostgreSQL reste nécessaire au runtime mais n'a aucun getter public dans `ksp-store-lib` et son `Debug` est redacted.
|
||||
|
||||
## Surface RawTransaction
|
||||
## Surface RAW
|
||||
|
||||
`Store` implémente les six capabilities transactionnelles acquises dans `ksp-store-api` :
|
||||
`Store` implémente exactement dix capabilities RAW backend-neutral :
|
||||
|
||||
```text
|
||||
RawTransactionRead
|
||||
@@ -74,24 +74,29 @@ RawTransactionObservationRead
|
||||
RawTransactionObservationWrite
|
||||
RawTransactionRetentionRead
|
||||
RawTransactionRetentionWrite
|
||||
RawAccountStateRead
|
||||
RawAccountStateWrite
|
||||
RawAccountObservationRead
|
||||
RawAccountObservationWrite
|
||||
```
|
||||
|
||||
Le consumer manipule uniquement les modèles et outcomes backend-neutral. Les erreurs physiques PostgreSQL sont projetées vers des codes Store stables sans exposer le backend.
|
||||
Pour `RawTransaction`, la façade fournit la lecture canonique et des observations, l'acquisition atomique transaction+observation, l'ajout idempotent d'observations, la pagination keyset et les transitions de rétention demandées par le caller.
|
||||
|
||||
La façade fournit ainsi :
|
||||
Pour `RawAccountState`, elle fournit :
|
||||
|
||||
- lecture d'une transaction canonique, de ses observations et de sa rétention ;
|
||||
- écriture atomique transaction + observation ;
|
||||
- ajout idempotent d'observations ;
|
||||
- pagination keyset déterministe par cursor opaque ;
|
||||
- application de transitions de rétention demandées par le caller ;
|
||||
- validation réseau avant dispatch lorsqu'un input porte explicitement son réseau.
|
||||
- lecture d'un état complet par référence durable `(network, pubkey, slot, state_hash)` ;
|
||||
- pagination keyset des références dans l'ordre total `(slot, pubkey, state_hash)`, avec filtre pubkey optionnel ;
|
||||
- écriture atomique état+observation avec idempotence exacte et conflit sur contenu divergent ;
|
||||
- lecture et ajout d'observations account ;
|
||||
- validation réseau avant dispatch pour les opérations dont l'input porte explicitement un réseau.
|
||||
|
||||
Les cursors restent opaques et propres à leur famille. Store ne leur attribue aucune sémantique de batch, priorité ou scheduling.
|
||||
|
||||
## Hors périmètre
|
||||
|
||||
Sont volontairement hors de cette surface :
|
||||
|
||||
- persistence/query/rétention PostgreSQL de `RawAccountState` ;
|
||||
- rétention, archivage, purge, delete ou compaction de `RawAccountState` ;
|
||||
- batch-size, priorité, backlog ou policy de worker/job ;
|
||||
- transport d'acquisition, Program decoding et materialization ;
|
||||
- exposition publique de SQL, pool, client, row, statement ou transaction PostgreSQL.
|
||||
@@ -105,4 +110,6 @@ Sont volontairement hors de cette surface :
|
||||
- [`../../docs/plans/023-V0_3_2_STORE_POSTGRES_FOUNDATION_PLAN.md`](../../docs/plans/023-V0_3_2_STORE_POSTGRES_FOUNDATION_PLAN.md) — plan de fondation ;
|
||||
- [`../../docs/validation/019-V0_3_2_STORE_POSTGRES_FOUNDATION.md`](../../docs/validation/019-V0_3_2_STORE_POSTGRES_FOUNDATION.md) — validation de fondation ;
|
||||
- [`../../docs/plans/024-V0_3_3_STORE_POSTGRES_RAW_TRANSACTION_PLAN.md`](../../docs/plans/024-V0_3_3_STORE_POSTGRES_RAW_TRANSACTION_PLAN.md) — plan `RawTransaction` ;
|
||||
- [`../../docs/validation/020-V0_3_3_STORE_POSTGRES_RAW_TRANSACTION.md`](../../docs/validation/020-V0_3_3_STORE_POSTGRES_RAW_TRANSACTION.md) — validation `RawTransaction`.
|
||||
- [`../../docs/validation/020-V0_3_3_STORE_POSTGRES_RAW_TRANSACTION.md`](../../docs/validation/020-V0_3_3_STORE_POSTGRES_RAW_TRANSACTION.md) — validation `RawTransaction` ;
|
||||
- [`../../docs/plans/025-V0_3_4_STORE_POSTGRES_RAW_ACCOUNT_PLAN.md`](../../docs/plans/025-V0_3_4_STORE_POSTGRES_RAW_ACCOUNT_PLAN.md) — design `RawAccountState` et complétude RAW ;
|
||||
- [`../../docs/validation/021-V0_3_4_STORE_POSTGRES_RAW_ACCOUNT.md`](../../docs/validation/021-V0_3_4_STORE_POSTGRES_RAW_ACCOUNT.md) — validation `RawAccountState` et conformance 10/10.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: crates/ksp-store-lib/USAGE.md -->
|
||||
<!-- version: 4 -->
|
||||
<!-- version: 5 -->
|
||||
|
||||
# Utilisation de ksp-store-lib
|
||||
|
||||
@@ -268,7 +268,98 @@ async fn archive_transaction(
|
||||
|
||||
Le backend PostgreSQL supporte physiquement `Full -> Archived -> Purged`. Une transition impliquant `Compacted` est rejetée par ce backend tant qu'aucune représentation compactée réelle n'est implémentée.
|
||||
|
||||
## 11. Diagnostics et erreurs
|
||||
## 11. Lire et paginer les états account RAW
|
||||
|
||||
Importer `RawAccountStateRead` donne accès à la lecture par référence et à la navigation déterministe.
|
||||
|
||||
```rust
|
||||
use ksp_store_lib::RawAccountStateRead;
|
||||
|
||||
async fn read_account_state(
|
||||
store: &ksp_store_lib::Store,
|
||||
reference: &ksp_store_lib::RawAccountStateReference,
|
||||
) -> ksp_store_lib::Result<std::option::Option<ksp_store_lib::RawAccountState>> {
|
||||
return store.get_raw_account_state(reference).await;
|
||||
}
|
||||
```
|
||||
|
||||
Pour une première page :
|
||||
|
||||
```rust
|
||||
use ksp_store_lib::RawAccountStateRead;
|
||||
|
||||
async fn first_account_page(
|
||||
store: &ksp_store_lib::Store,
|
||||
network: ksp_store_lib::RawNetworkId,
|
||||
pubkey: std::option::Option<ksp_store_lib::Pubkey>,
|
||||
) -> ksp_store_lib::Result<ksp_store_lib::RawPage<ksp_store_lib::RawAccountStateReference>> {
|
||||
let limit = ksp_store_lib::RawPageLimit::new(100);
|
||||
let limit = match limit {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
};
|
||||
|
||||
let slots = ksp_store_lib::RawSlotRange::new(std::option::Option::None, std::option::Option::None);
|
||||
let slots = match slots {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
};
|
||||
|
||||
let query = ksp_store_lib::RawAccountStateQuery::new(
|
||||
network,
|
||||
pubkey,
|
||||
slots,
|
||||
ksp_store_lib::RawSortDirection::Ascending,
|
||||
ksp_store_lib::RawPageRequest::first(limit),
|
||||
);
|
||||
|
||||
return store.list_raw_account_states(&query).await;
|
||||
}
|
||||
```
|
||||
|
||||
La continuation utilise uniquement `RawPage::next_cursor()` puis `RawPageRequest::after`. Le cursor account est opaque et lié au réseau, au filtre pubkey, à la direction et aux bornes de slots de la query qui l'a produit.
|
||||
|
||||
## 12. Persister une acquisition account
|
||||
|
||||
L'état canonique et son observation initiale sont une seule opération atomique.
|
||||
|
||||
```rust
|
||||
use ksp_store_lib::RawAccountStateWrite;
|
||||
|
||||
async fn persist_account_acquisition(
|
||||
store: &ksp_store_lib::Store,
|
||||
state: ksp_store_lib::RawAccountState,
|
||||
observation: ksp_store_lib::RawAccountObservation,
|
||||
) -> ksp_store_lib::Result<ksp_store_lib::RawAcquisitionWriteOutcome> {
|
||||
return store.persist_raw_account_acquisition(state, observation).await;
|
||||
}
|
||||
```
|
||||
|
||||
`state.reference()` et `observation.account()` doivent désigner exactement le même état et le réseau du `Store`. Une répétition byte-identique est idempotente ; un contenu divergent sous la même identité retourne `ERROR_CODE_RAW_CONFLICT`.
|
||||
|
||||
## 13. Lire et ajouter une observation account
|
||||
|
||||
```rust
|
||||
use ksp_store_lib::RawAccountObservationRead;
|
||||
use ksp_store_lib::RawAccountObservationWrite;
|
||||
|
||||
async fn use_account_observation(
|
||||
store: &ksp_store_lib::Store,
|
||||
key: &ksp_store_lib::RawObservationKey,
|
||||
observation: ksp_store_lib::RawAccountObservation,
|
||||
) -> ksp_store_lib::Result<ksp_store_lib::RawObservationWriteOutcome> {
|
||||
let existing = store.get_raw_account_observation(key).await;
|
||||
if let std::result::Result::Err(error) = existing {
|
||||
return std::result::Result::Err(error);
|
||||
}
|
||||
|
||||
return store.record_raw_account_observation(observation).await;
|
||||
}
|
||||
```
|
||||
|
||||
`record_raw_account_observation` ne crée jamais implicitement l'état canonique ; une référence absente retourne `ERROR_CODE_RAW_REFERENCE_NOT_FOUND`. `RawObservationKey` ne contient pas de réseau : la lecture par clé reste liée au backend mono-réseau déjà ouvert.
|
||||
|
||||
## 14. Diagnostics et erreurs
|
||||
|
||||
Les snapshots et erreurs de façade n'exposent ni URI, host, user, database, SQL, handle backend, valeur de bind ni texte d'erreur PostgreSQL.
|
||||
|
||||
@@ -286,8 +377,8 @@ store.postgres_retention_compaction_unsupported
|
||||
|
||||
Les conflits et queries invalides utilisent les codes backend-neutral `store_api.raw_conflict` et `store_api.raw_query_invalid`.
|
||||
|
||||
## 12. Limites de la façade
|
||||
## 15. Limites de la façade
|
||||
|
||||
La façade ne fournit pas d'accès public au SQL, au pool, aux clients ou transactions PostgreSQL. Les capabilities `RawAccount*` réexportées par l'API commune ne sont pas encore dispatchées par `Store`.
|
||||
La façade ne fournit pas d'accès public au SQL, au pool, aux clients ou transactions PostgreSQL. Elle dispatch les dix capabilities RAW de l'API commune, mais ne fournit aucune capability de rétention, archivage, purge, delete ou compaction account.
|
||||
|
||||
La taille de page est une primitive de navigation. Les décisions de batch, priorité, backlog et scheduling appartiennent aux workers/jobs, pas à Store.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: crates/ksp-store-postgres-lib/README.md -->
|
||||
<!-- version: 10 -->
|
||||
<!-- version: 11 -->
|
||||
|
||||
# ksp-store-postgres-lib
|
||||
|
||||
@@ -18,7 +18,7 @@ La crate possède seule pour PostgreSQL :
|
||||
- le bootstrap et le moteur de migrations privé KSP ;
|
||||
- la table metadata `ksp_store_schema_migrations` ;
|
||||
- l'advisory transaction lock borné des migrations ;
|
||||
- le schéma physique et les statements privés `RawTransaction` ;
|
||||
- les schémas physiques et statements privés `RawTransaction` et `RawAccountState` ;
|
||||
- les snapshots runtime/health sûrs destinés au bridge de façade ;
|
||||
- la fermeture explicite du pool et son fallback `Drop` best-effort ;
|
||||
- la classification d'erreurs backend sans conserver le texte d'erreur PostgreSQL.
|
||||
@@ -63,7 +63,7 @@ VerifyFull
|
||||
|
||||
Le moteur de migrations embarqué vérifie version logique, nom et checksum SHA-256, sérialise les runners par advisory transaction lock et refuse une history divergente ou plus récente que le runtime.
|
||||
|
||||
Le bootstrap metadata est conservé comme migration V000. La migration logique V001 matérialise le schéma `RawTransaction` en ressources séparées `tables/`, `constraints/` et `indexes/` afin que le backend puisse vérifier leur compatibilité effective sans transformer les fichiers SQL en parser généraliste.
|
||||
Le bootstrap metadata est conservé comme migration V000. La migration logique V001 matérialise le schéma `RawTransaction` et V002 le schéma `RawAccountState`, chacune en ressources séparées `tables/`, `constraints/` et `indexes/` afin que le backend puisse vérifier leur compatibilité effective sans transformer les fichiers SQL en parser généraliste.
|
||||
|
||||
La base est liée à un seul `RawNetworkId` via `ksp_store_identity`. Une migration enregistrée mais physiquement divergente est un mismatch ; les réparations additives sûres dépendent de `schema_autoupdate`.
|
||||
|
||||
@@ -130,11 +130,43 @@ Le backend verrouille la ligne canonique avec `FOR UPDATE`, compare l'état cour
|
||||
|
||||
Toute transition impliquant `Compacted` est rejetée avec `RetentionCompactionUnsupported` tant qu'aucune représentation compactée réelle n'est implémentée.
|
||||
|
||||
## Lectures RAW account
|
||||
|
||||
Le backend expose :
|
||||
|
||||
```text
|
||||
get_raw_account_state
|
||||
get_raw_account_observation
|
||||
```
|
||||
|
||||
`get_raw_account_state` reconstruit l'état complet à partir de `(pubkey, slot, state_hash)` sans narrowing du domaine `u64`. Les bytes `pubkey`, `owner` et `state_hash` sont revalidés à leur largeur exacte et `data` reste un `BYTEA` complet, vide autorisé, borné par le contrat Store API.
|
||||
|
||||
`get_raw_account_observation` reconstruit la provenance commune et les métadonnées account optionnelles, notamment `is_startup`, `transaction_signature` et `write_version`. La signature est une metadata fixed-width et ne crée aucune FK vers la famille transaction.
|
||||
|
||||
## Écritures RAW account
|
||||
|
||||
Le backend expose :
|
||||
|
||||
```text
|
||||
persist_raw_account_acquisition
|
||||
record_raw_account_observation
|
||||
```
|
||||
|
||||
L'acquisition état+observation est transactionnelle. Les inserts utilisent `ON CONFLICT ... DO NOTHING`, puis verrouillent et comparent le contenu gagnant avant de conclure `AlreadyPresent` ou `Conflict`; aucun `DO UPDATE` n'est utilisé. Une collision divergente d'observation fait échouer toute l'acquisition et rollback un éventuel nouvel état.
|
||||
|
||||
L'ajout d'une observation vérifie que l'état référencé existe déjà et ne crée jamais implicitement cet état.
|
||||
|
||||
## Pagination RAW account
|
||||
|
||||
`list_raw_account_states` parcourt les références selon l'ordre total `(slot, pubkey, state_hash)`, en ASC ou DESC, avec filtre pubkey optionnel. La continuation est keyset, sans `OFFSET`.
|
||||
|
||||
Le cursor `KSPA` est opaque et lié au réseau, au filtre pubkey, à la direction, aux bornes de slots et à la dernière clé complète. Il est distinct du cursor transaction `KSPT`.
|
||||
|
||||
## Hors périmètre
|
||||
|
||||
La crate ne contient :
|
||||
|
||||
- aucune implémentation PostgreSQL des capabilities `RawAccount*` ;
|
||||
- aucune rétention, archive, purge, suppression ou compaction account ;
|
||||
- aucune orchestration worker/job ;
|
||||
- aucun transport d'acquisition ou decoder Program ;
|
||||
- aucune policy autonome de batch, priorité ou rétention.
|
||||
@@ -147,4 +179,6 @@ La crate ne contient :
|
||||
- [`../../docs/plans/023-V0_3_2_STORE_POSTGRES_FOUNDATION_PLAN.md`](../../docs/plans/023-V0_3_2_STORE_POSTGRES_FOUNDATION_PLAN.md) — décisions pool/TLS/migrations ;
|
||||
- [`../../docs/validation/019-V0_3_2_STORE_POSTGRES_FOUNDATION.md`](../../docs/validation/019-V0_3_2_STORE_POSTGRES_FOUNDATION.md) — validation de fondation ;
|
||||
- [`../../docs/plans/024-V0_3_3_STORE_POSTGRES_RAW_TRANSACTION_PLAN.md`](../../docs/plans/024-V0_3_3_STORE_POSTGRES_RAW_TRANSACTION_PLAN.md) — design `RawTransaction` ;
|
||||
- [`../../docs/validation/020-V0_3_3_STORE_POSTGRES_RAW_TRANSACTION.md`](../../docs/validation/020-V0_3_3_STORE_POSTGRES_RAW_TRANSACTION.md) — validation `RawTransaction`.
|
||||
- [`../../docs/validation/020-V0_3_3_STORE_POSTGRES_RAW_TRANSACTION.md`](../../docs/validation/020-V0_3_3_STORE_POSTGRES_RAW_TRANSACTION.md) — validation `RawTransaction` ;
|
||||
- [`../../docs/plans/025-V0_3_4_STORE_POSTGRES_RAW_ACCOUNT_PLAN.md`](../../docs/plans/025-V0_3_4_STORE_POSTGRES_RAW_ACCOUNT_PLAN.md) — design `RawAccountState` et complétude RAW ;
|
||||
- [`../../docs/validation/021-V0_3_4_STORE_POSTGRES_RAW_ACCOUNT.md`](../../docs/validation/021-V0_3_4_STORE_POSTGRES_RAW_ACCOUNT.md) — validation `RawAccountState` et conformance RAW.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: crates/ksp-store-postgres-lib/USAGE.md -->
|
||||
<!-- version: 10 -->
|
||||
<!-- version: 11 -->
|
||||
|
||||
# Utilisation de ksp-store-postgres-lib
|
||||
|
||||
@@ -202,7 +202,58 @@ Le backend applique la transition choisie par le caller ; il ne décide pas de l
|
||||
|
||||
Une transition impliquant `Compacted` est refusée avec `PostgresBackendErrorKind::RetentionCompactionUnsupported` tant qu'aucune représentation compactée réelle n'est disponible.
|
||||
|
||||
## 11. Classifier les erreurs sans fuite
|
||||
## 11. Lire et paginer les états account
|
||||
|
||||
```rust
|
||||
async fn read_account_state(
|
||||
backend: &ksp_store_postgres_lib::PostgresBackend,
|
||||
reference: &ksp_store_api::RawAccountStateReference,
|
||||
) -> std::result::Result<std::option::Option<ksp_store_api::RawAccountState>, ksp_store_postgres_lib::PostgresBackendError> {
|
||||
return backend.get_raw_account_state(reference).await;
|
||||
}
|
||||
```
|
||||
|
||||
Pour la navigation, construire un `RawAccountStateQuery` puis appeler :
|
||||
|
||||
```rust
|
||||
async fn list_account_states(
|
||||
backend: &ksp_store_postgres_lib::PostgresBackend,
|
||||
query: &ksp_store_api::RawAccountStateQuery,
|
||||
) -> std::result::Result<ksp_store_api::RawPage<ksp_store_api::RawAccountStateReference>, ksp_store_postgres_lib::PostgresBackendError> {
|
||||
return backend.list_raw_account_states(query).await;
|
||||
}
|
||||
```
|
||||
|
||||
La pagination est keyset sur `(slot, pubkey, state_hash)` avec filtre pubkey optionnel. Le cursor `KSPA` est opaque, lié au contexte de query et distinct du cursor transaction.
|
||||
|
||||
## 12. Persister une acquisition account
|
||||
|
||||
```rust
|
||||
async fn persist_account_acquisition(
|
||||
backend: &ksp_store_postgres_lib::PostgresBackend,
|
||||
state: ksp_store_api::RawAccountState,
|
||||
observation: ksp_store_api::RawAccountObservation,
|
||||
) -> std::result::Result<ksp_store_api::RawAcquisitionWriteOutcome, ksp_store_postgres_lib::PostgresBackendError> {
|
||||
return backend.persist_raw_account_acquisition(state, observation).await;
|
||||
}
|
||||
```
|
||||
|
||||
Le backend exige le même réseau et la même référence complète entre l'état et l'observation avant l'I/O métier. L'opération est atomique et idempotente par comparaison exacte du contenu persistant ; un contenu divergent produit `PostgresBackendErrorKind::Conflict` sans overwrite silencieux.
|
||||
|
||||
## 13. Lire et ajouter une observation account
|
||||
|
||||
```rust
|
||||
async fn record_account_observation(
|
||||
backend: &ksp_store_postgres_lib::PostgresBackend,
|
||||
observation: ksp_store_api::RawAccountObservation,
|
||||
) -> std::result::Result<ksp_store_api::RawObservationWriteOutcome, ksp_store_postgres_lib::PostgresBackendError> {
|
||||
return backend.record_raw_account_observation(observation).await;
|
||||
}
|
||||
```
|
||||
|
||||
La lecture correspondante utilise `get_raw_account_observation`. L'ajout exige un état déjà durable et retourne `ReferenceNotFound` lorsqu'il manque. Les métadonnées Yellowstone optionnelles sont conservées sans créer de couplage physique vers `RawTransaction`.
|
||||
|
||||
## 14. Classifier les erreurs sans fuite
|
||||
|
||||
```rust
|
||||
fn classify(error: &ksp_store_postgres_lib::PostgresBackendError) {
|
||||
@@ -234,8 +285,8 @@ fn classify(error: &ksp_store_postgres_lib::PostgresBackendError) {
|
||||
|
||||
`PostgresBackendError` conserve uniquement une classification KSP et une phase statique. Ne pas reconstruire de diagnostic utilisateur à partir d'une erreur brute PostgreSQL.
|
||||
|
||||
## 12. Limites du backend direct
|
||||
## 15. Limites du backend direct
|
||||
|
||||
Le backend ne lit aucune variable d'environnement et ne possède aucune sélection de target Config. Les applications, jobs et workers doivent normalement passer par `ksp-store-lib`.
|
||||
|
||||
Les capabilities `RawAccount*` ne sont pas implémentées par ce backend. Les décisions de batch, priorité, backlog, scheduling et policy de rétention restent hors de sa responsabilité.
|
||||
Les dix capabilities RAW communes sont implémentées par ce backend. Les décisions de batch, priorité, backlog, scheduling et policy de rétention restent hors de sa responsabilité ; aucune rétention/archivage/purge account n'est fournie.
|
||||
|
||||
Reference in New Issue
Block a user