283 lines
13 KiB
Markdown
283 lines
13 KiB
Markdown
<!-- file: crates/ksp-worker-raw-transaction-ingest-lib/README.md -->
|
|
<!-- version: 5 -->
|
|
|
|
# ksp-worker-raw-transaction-ingest-lib
|
|
|
|
`ksp-worker-raw-transaction-ingest-lib` est le Worker concret KSP chargé de l'alimentation continue de la couche RAW Transaction.
|
|
|
|
La crate possède deux niveaux publics complémentaires :
|
|
|
|
```text
|
|
RawTransactionIngestWorker::start
|
|
-> fondation source-neutral, sans source productive
|
|
|
|
RawTransactionIngestWorker::start_with_runtime_resources
|
|
-> même runtime + une source productive supervisée
|
|
Yellowstone, WS standard logsSubscribe, WS standard blockSubscribe ou Helius transactionSubscribe
|
|
+ hydration HTTP getTransaction lorsque la source produit une référence
|
|
```
|
|
|
|
Le Worker reste indépendant de Config et de tout backend Store physique. Le caller compose les ressources Transport et Store, puis les remet à la crate par ses façades publiques.
|
|
|
|
## Pipeline productif actuel
|
|
|
|
Les verticales live productives sont :
|
|
|
|
```text
|
|
Yellowstone standard subscribe
|
|
-> Transaction / TransactionStatus / Block
|
|
-> signal source-neutral (network, signature, slot, commitment, provenance sûre)
|
|
|
|
Solana standard WS logsSubscribe
|
|
-> context.slot + signature
|
|
-> signal source-neutral (network, signature, slot, commitment, provenance sûre)
|
|
-> coalescence bornée par (network, signature, commitment)
|
|
-> HTTP getTransaction observed, Base64, maxSupportedTransactionVersion=1
|
|
|
|
Solana standard WS blockSubscribe
|
|
-> Full + Base64 + maxSupportedTransactionVersion=1 + showRewards=false
|
|
-> qualification explicite Legacy / V0 / V1
|
|
-> matériau Common RAW direct par transaction du bloc
|
|
|
|
Helius transactionSubscribe
|
|
-> Full + Base64 + maxSupportedTransactionVersion=1 + showRewards=false
|
|
-> signature + slot + transactionIndex uniquement dans le signal Worker
|
|
-> coalescence bornée par (network, signature, commitment)
|
|
-> HTTP getTransaction observed avant Common RAW
|
|
|
|
les chemins productifs
|
|
-> ksp-raw-transaction-lib
|
|
-> admission centrale bornée
|
|
-> ksp-store-lib
|
|
-> RawTransaction + RawTransactionObservation
|
|
```
|
|
|
|
`BlockMeta` et `Slot` ne produisent pas de RAW directement. Ils servent uniquement à la projection de continuité du run.
|
|
|
|
La qualification reste conservative : même lorsqu'une update Yellowstone contient une transaction complète côté protobuf, le Worker hydrate actuellement les signaux transactionnels par HTTP `getTransaction` avant de construire le RAW canonique. Il n'existe donc pas de second canonicaliseur Yellowstone.
|
|
|
|
## Contrat de source Yellowstone + HTTP
|
|
|
|
`RawTransactionIngestYellowstoneSource::new` reçoit :
|
|
|
|
```text
|
|
YellowstoneGrpcChannel
|
|
YellowstoneSubscribeRequest
|
|
HttpTransportPool
|
|
HttpRoleName d'hydration
|
|
```
|
|
|
|
La construction est sans I/O et refuse notamment :
|
|
|
|
- une requête Yellowstone invalide ;
|
|
- l'absence de famille porteuse d'ingestion ;
|
|
- un commitment `Processed` ou implicite ;
|
|
- un réseau Yellowstone non représentable ;
|
|
- une provenance provider/endpoint non représentable ;
|
|
- l'absence d'une route HTTP compatible pour `getTransaction` sur le même réseau.
|
|
|
|
Le runtime-resource aggregate public accepte une collection validée de 1 à 32 sources logiques. `pre.005` sait exécuter une source unique Yellowstone, Standard Logs, Standard Block ou Helius Transaction ; une activation simultanée de plusieurs sources reste rejetée avant spawn jusqu'au supervisor dédié. La collection interne, les `source_key`, les URLs, les filtres et les clients inférieurs ne sont pas exposés.
|
|
|
|
## Contrat de source Standard Logs + HTTP
|
|
|
|
`RawTransactionIngestStandardLogsSource::new` reçoit :
|
|
|
|
```text
|
|
WsEndpointSettings kind solana_standard
|
|
SolanaLogsSubscribeFilter
|
|
SolanaCommitment Confirmed ou Finalized
|
|
HttpTransportPool
|
|
HttpRoleName d'hydration
|
|
```
|
|
|
|
La construction est sans I/O. Elle refuse un endpoint WS invalide ou non standard, `Processed`, un réseau/provenance non représentable et l'absence de route HTTP `getTransaction` compatible sur le même réseau. Le filtre `All`, `AllWithVotes` ou `Mentions(pubkey)` participe uniquement à une empreinte privée ; le pubkey d'un filtre `Mentions` n'est pas recopié dans `Debug`, snapshot ou provenance textuelle.
|
|
|
|
Au runtime, le Worker ouvre `SolanaStandardWsSession::connect`, puis `logs_subscribe`. Les lignes de logs et `err` restent dans Transport et ne sont jamais stockées dans le signal Worker. Seuls `context.slot` et `signature` sont projetés vers l'hydration commune. Reconnect, resubscribe et backpressure de la subscription restent possédés par Transport.
|
|
|
|
## Contrat de source Standard Block direct RAW
|
|
|
|
`RawTransactionIngestStandardBlockSource::new` reçoit :
|
|
|
|
```text
|
|
WsEndpointSettings kind solana_standard
|
|
SolanaBlockSubscribeFilter
|
|
SolanaCommitment Confirmed ou Finalized
|
|
```
|
|
|
|
Le runtime ouvre la `SolanaStandardWsSession` existante et demande exactement `Base64`, `Full`, `maxSupportedTransactionVersion = 1` et `showRewards = false`. Aucun `HttpTransportPool` n'est attaché à cette source : les transactions dont la version est explicitement `Legacy`, `0` ou `1` sont transformées directement en `RawTransactionMaterial` à partir du wire Base64 du bloc, avec signature embarquée, slot, block time, meta, version et index de transaction.
|
|
|
|
La qualification est fermée : une version omise/nulle ou supérieure à `1`, une transaction non Base64, `block: null`, une erreur distante de notification, un slot de contexte incohérent ou un champ transactions absent/nul termine la source par une erreur sûre. Aucun de ces cas n'est converti en bloc vide, en succès silencieux ou en progression artificielle de frontier.
|
|
|
|
Pour un bloc multi-transaction, le slot n'est projeté settled qu'après l'admission réussie de toutes ses transactions. Cette voie RAW-direct n'incrémente pas `hydration_pending`; un stop ou une erreur au milieu du bloc ne produit aucune progression artificielle. Reconnect, resubscribe et backpressure WebSocket restent possédés par Transport.
|
|
|
|
## Contrat de source Helius Transaction + HTTP
|
|
|
|
`RawTransactionIngestHeliusTransactionSource::new` reçoit :
|
|
|
|
```text
|
|
WsEndpointSettings kind helius_laserstream
|
|
HeliusTransactionSubscribeFilter
|
|
SolanaCommitment Confirmed ou Finalized
|
|
HttpTransportPool
|
|
HttpRoleName d'hydration
|
|
```
|
|
|
|
La construction est sans I/O. Elle réutilise le contrat Transport existant et impose `Full`, `Base64`, `showRewards = false` et `maxSupportedTransactionVersion = 1`. Le Worker ne lit pas Config, ne lit pas `KSP_SECRET_HELIUS_API_KEY` et ne code aucun tier provider ; l'URL résolue et le credential restent dans l'endpoint Transport fourni par le caller.
|
|
|
|
Au runtime, `HeliusLaserStreamWsSession::connect` puis `transaction_subscribe` sont utilisés. Seule une notification `Full` conforme au mode demandé est admise ; une forme `Signature`, `Unknown` ou future devient une faute source sûre. Le payload Helius `transaction` n'est jamais copié dans l'état Worker : la projection conserve uniquement signature, slot et transaction index, puis réutilise le coordinateur d'hydration commun `getTransaction observed`.
|
|
|
|
La clé logique Helius inclut réseau, identités provider/endpoint sûres, commitment et empreinte privée du filtre. Les listes de pubkeys du filtre sont normalisées avant hash afin que leur ordre ne crée pas artificiellement deux sources logiques ; le rôle HTTP d'hydration reste exclu de l'identité live.
|
|
|
|
## Runtime et lifecycle
|
|
|
|
Le Worker s'exécute sur le runtime Tokio courant du caller. Il ne crée pas de runtime global et n'expose aucun `JoinHandle` public.
|
|
|
|
`RawTransactionIngestHandle` permet de :
|
|
|
|
- demander un stop coopératif et idempotent ;
|
|
- lire une source de snapshots concrets latest-value ;
|
|
- utiliser la même source via `WorkerSnapshotSource` ;
|
|
- attendre le terminal après drain et join des tâches possédées.
|
|
|
|
Le shutdown est borné par `shutdown_drain_timeout`. Les tâches source, hydration et persistence possédées sont drainées ou abort+join avant publication terminale. L'abandon terminal d'une hydration retire son pending run-local sans le convertir artificiellement en travail `settled`.
|
|
|
|
## Admission, coalescence et backpressure
|
|
|
|
La queue centrale est un `tokio::sync::mpsc` privé borné par `admission_queue_capacity`. Les sources internes subissent la backpressure ; aucune queue non bornée ni silent drop n'est autorisé.
|
|
|
|
Le Worker possède un coordinateur d'hydration source-neutral borné, réutilisé par Yellowstone, Standard Logs et Helius Transaction. Standard Block n'entre pas dans ce coordinateur lorsqu'une transaction est direct-qualified :
|
|
|
|
```text
|
|
in-flight hydration <= persistence_concurrency
|
|
pending source signals <= admission_queue_capacity
|
|
```
|
|
|
|
Les signaux partageant le même `(network, signature, commitment)` sont coalescés avant le fan-out HTTP. Les provenances utiles restent néanmoins conservées pour les ingress produits après hydration.
|
|
|
|
Les retries/reroutages HTTP appartiennent à `ksp-onchain-transport-lib`. Le Worker ne possède pas une seconde boucle de retry autour de `getTransaction`.
|
|
|
|
## Processing frontier run-local
|
|
|
|
Le snapshot expose :
|
|
|
|
```text
|
|
hydration_pending
|
|
processing_frontier_slot
|
|
oldest_pending_slot
|
|
```
|
|
|
|
Cette frontier mesure uniquement le traitement des signaux réellement observés pendant le run courant. Elle n'est ni un checkpoint durable, ni une preuve de complétude blockchain, ni un curseur de Backfill.
|
|
|
|
Un signal transactionnel devient pending après validation de sa clé d'hydration et insertion dans le coordinateur. Il devient settled pour la source lorsque :
|
|
|
|
```text
|
|
getTransaction -> Missing
|
|
ou
|
|
getTransaction -> Available puis ingress envoyé avec succès vers l'admission centrale
|
|
```
|
|
|
|
Un `BlockMeta` ou `Slot` continuity-only est settled localement sans produire de RAW. La frontier n'avance jamais à travers le plus ancien pending connu.
|
|
|
|
## Reconnect, replay et continuité
|
|
|
|
Le reconnect/replay Yellowstone appartient à Transport. Le Worker n'écrit pas `from_slot` et n'interprète pas directement `SubscribeReplayInfo`.
|
|
|
|
Le snapshot Worker projette uniquement des informations sûres :
|
|
|
|
```text
|
|
source_state
|
|
source_reconnect_total
|
|
source_replay_attempt_total
|
|
source_continuity_gap_total
|
|
```
|
|
|
|
`RawTransactionIngestSourceState` distingue :
|
|
|
|
```text
|
|
Active
|
|
Reconnecting
|
|
Closing
|
|
Closed
|
|
Failed
|
|
```
|
|
|
|
Un replay attempt n'est pas une preuve de replay réussi ni de continuité parfaite. Si Transport augmente son compteur de continuity gap parce que la borne de rétention prouve que le slot demandé n'est plus rejouable, le Worker classe la source en failure et termine avec `worker_raw_transaction_ingest.source_failed`.
|
|
|
|
Le Worker ne lance alors ni Job Backfill ni campagne historique automatique.
|
|
|
|
## Persistence Store
|
|
|
|
La persistance passe exclusivement par `ksp-store-lib` avec `default-features = false`. Aucun backend physique n'est importé directement.
|
|
|
|
L'écriture utilise le mode normal atomique `RawTransaction + RawTransactionObservation`. Les outcomes distingués incluent :
|
|
|
|
```text
|
|
entity inserted
|
|
entity already present
|
|
entity skipped purged
|
|
observation inserted
|
|
observation already present
|
|
observation not recorded for purged entity
|
|
content conflict
|
|
store failure
|
|
```
|
|
|
|
Un content conflict est terminal et n'est jamais converti en succès idempotent.
|
|
|
|
## Snapshots et erreurs
|
|
|
|
`RawTransactionIngestSnapshotSource` est latest-value : les lecteurs peuvent rater des transitions intermédiaires mais récupèrent toujours la dernière projection complète et monotone.
|
|
|
|
Les codes Worker publics sont :
|
|
|
|
```text
|
|
worker_raw_transaction_ingest.settings_invalid
|
|
worker_raw_transaction_ingest.runtime_invalid
|
|
worker_raw_transaction_ingest.store_failed
|
|
worker_raw_transaction_ingest.content_conflict
|
|
worker_raw_transaction_ingest.counter_exhausted
|
|
worker_raw_transaction_ingest.source_failed
|
|
worker_raw_transaction_ingest.drain_timeout
|
|
```
|
|
|
|
Les diagnostics et `Debug` ne recopient pas de payload RAW, signature, URL, credential, filtre provider, texte backend/provider arbitraire ou client inférieur.
|
|
|
|
## Dépendances
|
|
|
|
Les dépendances normales sont exactement :
|
|
|
|
```text
|
|
ksp-core-lib
|
|
ksp-logging-lib
|
|
ksp-onchain-transport-lib
|
|
ksp-raw-transaction-lib
|
|
ksp-store-lib (default-features = false)
|
|
ksp-worker-api
|
|
sha2
|
|
tokio (macros, rt, sync, time)
|
|
```
|
|
|
|
La crate ne dépend pas de Config, Job, `ksp-store-api` directement, backend Store concret, `reqwest`, `tonic`, `yellowstone-grpc-proto` ou Tauri.
|
|
|
|
## Hors périmètre
|
|
|
|
La verticale actuelle ne possède pas :
|
|
|
|
- plusieurs sources productives simultanées dans `RawTransactionIngestRuntimeResources` ;
|
|
- source HTTP live polling Worker ;
|
|
- sélection Config interne au Worker ;
|
|
- checkpoint persistent de processing frontier ;
|
|
- campagne de réparation historique automatique ;
|
|
- application Desk ou process autonome ;
|
|
- décodage STRUCTURAL/DECODED/DOMAIN.
|
|
|
|
Les futures extensions doivent conserver la séparation avec `ksp-job-backfill-lib` et réutiliser les mêmes contrats Common RAW/Store.
|
|
|
|
## Documentation
|
|
|
|
- [`USAGE.md`](USAGE.md) — utilisation de la façade publique ;
|
|
- [`../ksp-worker-api/README.md`](../ksp-worker-api/README.md) — contrats Worker génériques ;
|
|
- [`../ksp-raw-transaction-lib/README.md`](../ksp-raw-transaction-lib/README.md) — canonicalisation RAW commune ;
|
|
- [`../../docs/architecture/009-ACQUISITION_WORKERS_AND_JOBS.md`](../../docs/architecture/009-ACQUISITION_WORKERS_AND_JOBS.md) — séparation Worker/Job ;
|
|
- [`../../docs/architecture/011-RAW_TRANSACTION_ACQUISITION.md`](../../docs/architecture/011-RAW_TRANSACTION_ACQUISITION.md) — architecture d'acquisition RawTransaction.
|