10 KiB
Delta 0.3.4-pre.004 — mapping PostgreSQL privé et lectures RawAccountState
1. Base requise
0.3.4-pre.3.fix.1
Le gate opérateur fourni le 2026-08-30 pour pre.003-fix.001 est entièrement vert :
cargo fmt --all PASS
audit Rust général / exports / workspace PASS
audit Markdown PASS — 239 tables / 139 files
cargo check --workspace PASS
cargo clippy --workspace --all-targets PASS
cargo test -p ksp-store-api PASS
cargo test -p ksp-store-lib PASS
cargo test -p ksp-store-postgres-lib PASS — 45 unit tests + canaris, live ignored
cargo test -p ksp-config-lib PASS — 128 unit tests + ownership/public API
cargo check -p ksp-store-lib --no-default-features PASS
V002 finale et son checksum sont donc considérés acquis avant l'ouverture du mapping account.
2. Objectif
Implémenter la tranche de lecture de la vertical slice PostgreSQL RawAccountState sans ouvrir les writes, la pagination ni les implémentations de traits :
mapping SQL privé state
mapping SQL privé observation
get_raw_account_state
get_raw_account_observation
hostile-row guards
Les méthodes du backend retournent uniquement des modèles ksp-store-api. Aucun tokio_postgres::Row, SQL, bind, SQLSTATE ou type physique ne traverse le bridge public.
3. Version
Le workspace passe à :
0.3.4-pre.4
Aucune crate ne redéfinit localement la version héritée.
4. Module physique privé
Nouveau module :
crates/ksp-store-postgres-lib/src/raw_account.rs
Il possède les deux SELECT et les codecs physiques de cette tranche. runtime.rs ne contient aucun SQL métier et délègue les lectures au module privé.
La tranche est strictement read-only :
INSERT INTO absent
UPDATE absent
DELETE FROM absent
ON CONFLICT absent
FOR UPDATE absent
list/cursor account absent
Les écritures state+observation restent pre.005, l'observation supplémentaire pre.006, la pagination/cursor pre.007 et les quatre impl RawAccount* pre.008.
5. get_raw_account_state
Le SELECT adresse exactement la clé physique :
(pubkey, slot, state_hash)
Le mapping reconstruit :
network <- backend mono-réseau
pubkey <- BYTEA exactement 32 bytes
slot <- NUMERIC(20,0)::text -> u64
state_hash <- BYTEA exactement 32 bytes
lamports <- NUMERIC(20,0)::text -> u64
owner <- BYTEA exactement 32 bytes
executable <- BOOLEAN
rent_epoch <- NUMERIC(20,0)::text -> u64
data <- BYTEA exact -> RawAccountState::try_new
Le chemin décimal couvre tout le domaine u64, y compris les valeurs supérieures à i64::MAX et u64::MAX lui-même. Aucun narrowing via BIGINT n'est introduit.
RawAccountState::try_new revalide la borne backend-agnostic des bytes account : data vide est valide ; une ligne hostile dépassant 16 MiB devient DataInvalid.
Après décodage, la référence reconstruite doit rester exactement égale à la référence demandée. Une cardinalité autre que 0/1 est également DataInvalid.
6. Garde réseau pré-I/O
get_raw_account_state vérifie avant pool.get() :
reference.network == backend.network -> continuer
sinon -> WrongNetwork
Le mauvais réseau ne consomme donc aucune connexion PostgreSQL et n'expose aucune valeur fournie.
7. get_raw_account_observation
RawObservationKey ne porte pas de réseau. Le réseau de la RawAccountStateReference reconstruite provient donc exclusivement du backend mono-réseau déjà lié par ksp_store_identity.
Le mapping couvre :
observation_key
account.pubkey
account.slot
account.state_hash
provider
protocol
acquisition_method
origin
received_at
capture_session_id optionnel
commitment optionnel
endpoint_id optionnel
filter_id optionnel
observed_at optionnel
source_payload_hash optionnel
source_payload_size_bytes optionnel
is_startup optionnel
transaction_signature optionnelle
write_version optionnel
Spécificités physiques :
account.slot / write_version -> NUMERIC(20,0)::text -> u64
transaction_signature -> NULL ou exactement 64 bytes
hash/key/pubkey -> exactement 32 bytes
received/observed -> BIGINT -> u64 -> RawTimestamp
source payload size -> BIGINT -> u64 + borne API 64 MiB
provenance codes -> constructeurs API fallibles
origin -> cinq variantes API uniquement
Les metadata Yellowstone restent strictement observation-only. Une colonne NULL reste None; aucune valeur false, zéro, signature ou write version n'est inventée.
8. Hostile-row guards
Les tests unitaires couvrent notamment :
state slot/lamports/rent_epoch = u64::MAX
write_version = u64::MAX
account data vide
account data > 16 MiB -> DataInvalid
pubkey de 31 bytes -> DataInvalid
signature transaction de 63 bytes -> DataInvalid
décimal négatif ou > u64::MAX -> DataInvalid
origin hostile -> DataInvalid
observed_at > received_at -> DataInvalid
metadata optionnelles absentes -> None
wrong network state reference -> WrongNetwork pré-I/O
Les erreurs ne retiennent que PostgresBackendErrorKind + phase &'static str; les chaînes hostiles ne sont jamais interpolées dans l'erreur.
9. Surface backend
PostgresBackend expose désormais le bridge étroit :
get_raw_account_state
get_raw_account_observation
Ces méthodes ne constituent pas encore les implémentations de RawAccountStateRead et RawAccountObservationRead : le premier trait exige aussi list_raw_account_states, réservé à pre.007. Les quatre traits account seront ouverts ensemble en pre.008 afin de passer directement de 6/10 à 10/10 capabilities physiques.
10. Canaries transformés
Les canaris historiques qui interdisaient tout module account sont ajustés sans perdre leur rôle :
dependency_boundary.rsexige un moduleraw_accountprivé, read-only, sans pagination ni trait impl ;hardening_completeness.rsinclut le nouveau module dans l'inventaire exact et dans les scans anti-secret/anti-reverse-edge ;- les interdictions des quatre
impl RawAccount* for PostgresBackendrestent actives ; public_api.rsprouve que les deux méthodes du bridge n'utilisent que les modèles backend-agnostic.
Les canaris V000/health business-free restent inchangés.
11. Migrations
Aucune ressource sous migrations/ n'est modifiée.
Checksums conservés :
V000 = d29068b8c13b9dc0cc9ef6aaadd0fa12d41e0fe4c56541a1118c4bfc846a1450
V001 = 31488cda2f08f3f46c4cdbdbb6c18c243662fada02eac4487040c8735d72cc51
V002 = ff21605ed45f7ab4c0f92bbb692700b4118a9488b04d50a31d259ac59bdb550e
Le bridge du checksum provisoire pre.002 reste inchangé.
12. Fichiers ajoutés
crates/ksp-store-postgres-lib/src/raw_account.rs
crates/ksp-store-postgres-lib/unit_tests/raw_account.rs
deltas/0.3.4/pre.004.md
13. Fichiers modifiés
Cargo.toml
crates/ksp-store-postgres-lib/src/lib.rs
crates/ksp-store-postgres-lib/src/runtime.rs
crates/ksp-store-postgres-lib/tests/dependency_boundary.rs
crates/ksp-store-postgres-lib/tests/hardening_completeness.rs
crates/ksp-store-postgres-lib/tests/public_api.rs
docs/plans/025-V0_3_4_STORE_POSTGRES_RAW_ACCOUNT_PLAN.md
docs/validation/021-V0_3_4_STORE_POSTGRES_RAW_ACCOUNT.md
14. Fichiers supprimés
aucun
15. Validations exécutées
Dans l'environnement d'assemblage :
python3 scripts/audit_rust_workspace_rules.py
General Rust rule audit: clean
Rust export completeness audit: 0 candidate(s)
KSP workspace Rust rule audit: clean
python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates deltas/0.3.4
PASS après alignement RustRover des tableaux touchés
Le contrôle différentiel doit également confirmer qu'aucune ressource V000/V001/V002 n'a changé.
16. Validations non exécutées dans l'environnement d'assemblage
cargo, rustc et rustfmt ne sont pas disponibles dans cet environnement. Ne sont donc pas revendiqués PASS ici :
cargo fmt --all
cargo check --workspace
cargo clippy --workspace --all-targets
cargo test -p ksp-store-api
cargo test -p ksp-store-lib
cargo test -p ksp-store-postgres-lib
cargo test -p ksp-config-lib
cargo check -p ksp-store-lib --no-default-features
17. Décisions prises
- Réutiliser la frontière éprouvée de
0.3.3-pre.004: SQL/mapping privé, méthodes backend étroites, traits plus tard. - Garder les conversions
NUMERIC(20,0)via::text -> u64afin de ne pas ajouter de dépendance décimale ni de narrowing. - Revalider les invariants API au read même si V002 possède déjà des CHECK SQL ; la DB peut être externe, héritée ou hostile.
- Ne pas factoriser prématurément les codecs transaction/account dans un nouveau module commun : les familles ont des formes différentes et
pre.004doit rester bornée. - Ne pas ouvrir
RawAccountStateReadavant quelist_raw_account_statesexiste ; l'inventaire de capabilities reste volontairement 6/10 jusqu'àpre.008.
18. Questions ouvertes
Aucune question bloquante nouvelle. Les détails des writes, races et cursor restent ceux figés par le plan pre.001 et appartiennent respectivement à pre.005, pre.006 et pre.007.
19. Gate opérateur attendu
cargo fmt --all
python3 scripts/audit_rust_workspace_rules.py
python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates deltas/0.3.4
cargo check --workspace
cargo clippy --workspace --all-targets
cargo test -p ksp-store-api
cargo test -p ksp-store-lib
cargo test -p ksp-store-postgres-lib
cargo test -p ksp-config-lib
cargo check -p ksp-store-lib --no-default-features
Aucun test live PostgreSQL account n'est demandé dans cette tranche ; la preuve live complète reste pre.009.