113 lines
4.9 KiB
Markdown
113 lines
4.9 KiB
Markdown
<!-- file: docs/INSTRUCTION_REPLAY_CONTRACTS.md -->
|
|
<!-- version: 4 -->
|
|
|
|
# Contrats de replay par instruction
|
|
|
|
Ce document complète le cadrage `0.2.1`. Il ne crée pas encore le schéma SQL complet, mais il verrouille l'idée suivante : le scheduling de replay doit cibler les instructions normalisées, tandis que le décodage doit recevoir une instruction avec son contexte Solana extrait.
|
|
|
|
## Motivation
|
|
|
|
Une transaction Solana peut contenir plusieurs instructions top-level et plusieurs inner instructions. Certaines instructions peuvent être déjà décodées, d'autres non. Rejouer toute la transaction à chaque correction de décodeur serait plus coûteux et moins précis.
|
|
|
|
Le pipeline doit donc pouvoir faire :
|
|
|
|
```text
|
|
raw transaction
|
|
→ extraction core transaction
|
|
→ extraction account keys, instructions, inner instructions, logs, balances
|
|
→ sélection des instructions non traitées
|
|
→ reconstruction d'un replay input contextualisé
|
|
→ decode/materialize uniquement sur ces inputs
|
|
```
|
|
|
|
## Scheduling instruction-level
|
|
|
|
L'état `CoreInstructionProcessingState` prépare cette granularité.
|
|
|
|
| État | Sens |
|
|
|-------------------|---------------------------------------------------------------|
|
|
| `Pending` | Instruction disponible pour premier traitement. |
|
|
| `Decoded` | Instruction décodée par au moins un décodeur. |
|
|
| `Materialized` | Instruction ayant produit une projection métier. |
|
|
| `Ignored` | Instruction ignorée volontairement par la politique courante. |
|
|
| `Failed` | Instruction en échec, à diagnostiquer. |
|
|
| `ReplayRequested` | Instruction à rejouer même si un traitement précédent existe. |
|
|
|
|
Les états ne remplacent pas le ledger par module/version. Ils servent de vue rapide et de filtre de scheduling.
|
|
|
|
## Décodage contextualisé
|
|
|
|
Le décodeur ne doit pas être limité à `CoreInstructionRow.payload_json`.
|
|
|
|
Certains protocoles Solana exigent de lire :
|
|
|
|
- les inner instructions ;
|
|
- les logs Anchor ou non Anchor ;
|
|
- les balances avant/après ;
|
|
- les comptes résolus ;
|
|
- les loaded addresses ;
|
|
- les erreurs de transaction ;
|
|
- des séquences de logs liées à un CPI ;
|
|
- des instructions voisines de la même transaction.
|
|
|
|
`MdCoreInstructionReplayInput` représente ce contrat de lecture : une instruction ciblée plus un contexte extrait depuis les tables `core`. Depuis le contrat `2`, ce contexte inclut également toutes les instructions outer de la signature, ordonnées numériquement et munies de leur payload retenu et de son hash.
|
|
|
|
## Sélection de replay
|
|
|
|
`CoreInstructionReplayFilter` permet de sélectionner les instructions par :
|
|
|
|
- état de traitement ;
|
|
- `program_id` ;
|
|
- plage de slots.
|
|
|
|
L'usage standard pour un worker de decode sera :
|
|
|
|
```text
|
|
processing_state = Pending ou ReplayRequested
|
|
program_id = programme ciblé par le décodeur
|
|
plage de slots = optionnelle
|
|
```
|
|
|
|
Le repository charge les logs, balances, account keys et instructions outer nécessaires pour retourner `MdCoreInstructionReplayInput`. La liste outer inclut la cible et utilise les champs stables `instructionIndex`, `instructionPath`, `programId`, `payloadJson` et `payloadHash`. Cette extension lit les tables existantes et ne demande aucune migration.
|
|
|
|
## Marquage de cycle de vie
|
|
|
|
`CoreInstructionLifecycleMark` permet à un module de changer l'état d'une instruction après traitement.
|
|
|
|
Exemples :
|
|
|
|
- un décodeur reconnu marque l'instruction `Decoded` ;
|
|
- un materializer complet marque l'instruction `Materialized` ;
|
|
- un décodeur non concerné peut marquer `Ignored` dans un contexte contrôlé ;
|
|
- une erreur de parsing marque `Failed` ;
|
|
- une correction de décodeur peut remettre `ReplayRequested`.
|
|
|
|
## Relation avec `kb_sol_ops_processing_ledger`
|
|
|
|
Le processing ledger garde le détail par module, version et input. L'état sur l'instruction reste le dernier état opérationnel visible.
|
|
|
|
Pour éviter les doublons, l'input key du ledger devra être stable, par exemple :
|
|
|
|
```text
|
|
signature:instruction_path:program_id:processor_name:processor_version
|
|
```
|
|
|
|
La forme exacte n'est pas figée en `0.2.1`, mais elle doit rester déterministe.
|
|
|
|
## Rétention du payload d'instruction et des logs
|
|
|
|
Le payload JSON d'une instruction et le texte des logs sont utiles au début. Plus tard, après décodage et matérialisation fiables, ils pourront être compactés ou purgés avec conservation d'un hash.
|
|
|
|
Les entities `CoreInstructionRow` et `CoreLogRow` préparent ce cas en autorisant :
|
|
|
|
- payload ou texte présent ;
|
|
- payload ou texte absent ;
|
|
- hash conservé ;
|
|
- état de traitement consultable pour replay.
|
|
|
|
La purge effective ne doit pas être implémentée avant que les diagnostics de replay soient fiables.
|
|
|
|
## Décision pour `0.2.1`
|
|
|
|
`0.2.1` ajoute les contrats Rust nécessaires, mais ne crée pas encore les tables SQL. Les migrations réelles restent prévues pour `0.2.3` et `0.2.4`.
|