7.7 KiB
Modèle d’acquisition des transactions Solana
Décision
Le pipeline ne conserve pas un payload complet différent pour chaque fournisseur. Toutes les sources doivent produire une représentation canonique commune avant l’écriture principale.
getTransaction JSON-RPC
Helius transactionSubscribe JSON
Yellowstone gRPC Protobuf
logsSubscribe + getTransaction
backfill ou réparation
|
v
adaptateur de source dans kb_rpc
|
v
transaction Solana canonique
|
+--> kb_sol_raw_transactions
|
+--> kb_sol_obs_transaction_observations
Transaction canonique
kb_sol_raw_transactions contient une seule ligne par signature. Le contenu est indépendant du fournisseur et ne doit contenir aucun champ propre à Helius, Triton, Chainstack, Shyft ou un endpoint particulier.
Le document canonique doit inclure, quand la source les fournit :
- signature ;
- slot ;
- version de transaction ;
- message header ;
- static account keys ;
- Address Lookup Tables ;
- loaded writable et readonly addresses ;
- recent blockhash ;
- outer instructions ;
- inner instructions ;
- logs ;
- statut et erreur ;
- fee et compute units ;
- balances SOL avant/après ;
- balances SPL avant/après ;
- rewards ;
- return data ;
- block time.
Les public keys et signatures restent en base58, avec validation stricte de leur taille décodée : 32 octets pour les clés et blockhashes, 64 octets pour les signatures. Les données binaires d’instruction restent en base64. Les montants SPL conservent le montant entier brut normalisé sans zéros non significatifs, les décimales et une représentation décimale fixe recalculée localement, sans dépendre de uiAmount ou uiAmountString du fournisseur.
Depuis 0.3.2, ce contrat est matérialisé par kb_model::CanonicalTransaction avec canonical_format_version = 1. La sérialisation trie récursivement les clés des objets JSON avant calcul d’un hash SHA-256 sur le document compact. Les tableaux conservent l’ordre Solana d’origine. Les détails de source, timestamps locaux et identifiants de subscription sont exclus du document hashé.
L’adaptateur HTTP standard demande encoding = json, puis convertit explicitement les payloads d’instruction reçus en base58 vers la représentation base64 canonique. Les champs optionnels absents et null sont normalisés vers le même état interne afin de stabiliser le hash entre réponses compatibles.
Observations de source
kb_sol_obs_transaction_observations décrit comment et quand une transaction a été détectée ou reçue. Elle ne duplique pas la transaction complète.
Champs minimaux visés :
| Champ | Rôle |
|---|---|
observation_key |
clé idempotente de l’observation |
raw_transaction_id |
lien optionnel vers la transaction canonique |
signature |
signature observée |
slot |
slot observé quand connu |
provider |
fournisseur, par exemple helius, triton, chainstack, shyft |
endpoint_code |
endpoint de configuration utilisé |
protocol |
solana_http_json_rpc, solana_ws_json_rpc, helius_ws ou yellowstone_grpc |
acquisition_method |
getTransaction, transactionSubscribe, yellowstone_transactions, logs_hydration, etc. |
origin |
live, backfill, replay, repair ou migration |
commitment |
commitment demandé ou observé |
capture_session_id |
session ou campagne de capture |
filter_code |
profil de filtre utilisé |
detected_at |
réception du premier signal, par exemple le log |
received_at |
réception de la transaction complète |
normalized_at |
fin de normalisation canonique |
persisted_at |
fin d’écriture durable |
payload_size_bytes |
taille du message source reçu |
source_payload_hash |
hash optionnel du message source sans le conserver |
status |
detected, received, normalized, persisted, failed ou missing |
error_code |
code technique normalisé optionnel |
error_message |
message de diagnostic optionnel |
Les observations permettent de comparer les sources par signature, sans multiplier le volume de stockage transactionnel.
Notifications WebSocket
kb_sol_raw_ws_notifications n’est plus une cible durable.
Une notification logsSubscribe peut être conservée temporairement en mémoire jusqu’à l’hydratation de la transaction. La base conserve ensuite seulement :
- les timestamps utiles ;
- la signature et le slot ;
- la source et la méthode ;
- la taille ;
- le statut de l’hydratation ;
- le lien éventuel vers la transaction canonique.
Les notifications non transactionnelles comme slotSubscribe, accountSubscribe ou programSubscribe pourront avoir des tables métier dédiées seulement si un besoin durable apparaît. Elles ne doivent pas être entassées dans une table générique de payloads WebSocket.
Fusion multi-source
Pour une signature déjà présente :
- normaliser le nouveau message ;
- calculer le hash canonique ;
- ajouter l’observation de source ;
- si le hash est identique, ne pas dupliquer la transaction ;
- si la nouvelle source apporte uniquement des champs auparavant absents, appliquer un enrichissement déterministe ;
- si des champs incompatibles diffèrent, ne pas écraser silencieusement et enregistrer un conflit technique.
Les différences liées au commitment ou à la disponibilité progressive des metadata doivent être distinguées d’un conflit réel.
Raw provider facultatif
Un payload fournisseur complet peut être exporté de façon bornée pour une campagne de diagnostic, par exemple en NDJSON ou Protobuf, mais il ne fait pas partie du stockage PostgreSQL transactionnel normal.
Ces exports doivent être :
- explicitement activés ;
- limités en durée et en volume ;
- associés à une session de capture ;
- supprimables sans affecter les replays métier.
Frontières des crates
kb_rpccontient les transports et adaptateurs HTTP, WebSocket Helius et Yellowstone gRPC.kb_modelcontient le contrat canonique source-indépendant.kb_store_corecontient les DTOs et repositories de transactions et observations.kb_store_pgcontient la migration, les queries et les repositories PostgreSQL.- les décodeurs ne dépendent jamais de la source d’acquisition.