kb_decoder_solana_core
Ce crate décode les programmes Solana natifs/runtime, les programmes historiques encore observables, les loaders et les précompiles. memo est explicitement exclu de cette crate et appartient à la série SPL.
Rôle dans l'écosystème
SolanaCoreDecoder implémente le contrat commun InstructionDecoder et consomme uniquement les inputs contextualisés produits par l’extraction core. Il ne dépend ni de PostgreSQL, ni de Tauri, ni d’un fournisseur RPC.
Le processor conserve l’identité stable solana_native_classifier introduite en 0.4.0. Cette continuité permet au ledger processor/version/hash de remplacer les anciens résultats unsupported lors d’un force replay. La version du processor reste 0.4.1 pendant les deltas préparatoires.
Couverture 0.4.1-pre.018
Les deltas préparatoires de 0.4.1 livrent les phases A à E et poursuivent l’audit final :
- utilitaires de lecture base64 bornée et de lecture little-endian ;
- validation des comptes résolus et attribution de rôles officiels ;
- événements natifs versionnés, déterministes et explicites sur le succès on-chain ;
- décodage des quatorze variantes actuelles de
SystemInstructiondepuissolana-system-interface 3.2.0; - décodage des variantes Compute Budget actuelles depuis
solana-compute-budget-interface 3.0.0, avec compatibilité runtime Borsh unchecked : valeurs minimales décodées et suffixes conservés par taille, préfixe et SHA-256 ; - prise en charge historique de
RequestUnitsDeprecated; - distinction entre
decoded,ignored,unsupportedetfailed; - absence de mutation commitée pour une transaction source échouée ;
- décodage exact des cinq variantes Address Lookup Table depuis
solana-address-lookup-table-interface 3.1.0; - gestion de la paire optionnelle payer/System lors d’un extend et de la règle signer historique de l’autorité lors d’un create ;
- projection lifecycle ALT séparée dans
kb_materializer_lifecyclepour les observations réussies et commitées ; - conservation des comptes System additionnels correctement résolus avec le rôle
additional_account, après validation sur un transfert mainnet réussi ; - décodage exact des loaders BPF immuables, upgradeable et v4 avec tailles canoniques, champs historiques optionnels et hashes des blocs écrits ;
- classification de l’invocation directe du Native Loader comme
ignored, car aucune enum d’instruction autonome stable n’est publiée ; - projection lifecycle des finalize/deploy/upgrade/close/extend/retract/set length réussis ;
pre.020projette séparément les changements d’autorité danskb_materializer_adminet les writes/copies de bytecode danskb_materializer_compliance_audit, avec hash et préfixe borné ; - décodage de
FeatureGateInstruction::RevokePendingActivationavec validation des comptes Feature, Incinerator et System ; - décodage générique du Config Program : clés compactes, signataires et payload opaque borné/hashé ;
- exclusion de Stake Config des surfaces, car son adresse désigne un compte historique non exécutable ;
- décodage exact des vingt variantes
VoteInstructiondesolana-vote-interface ^6.0viawincode::deserialize_exact, y compris les formes checked/seed, compactes, tower sync, initialisation V2 avec BLS, commissions différenciées et dépôt de récompenses délégateurs ; - validation des sysvars Rent, Clock et Slot Hashes aux positions officielles, tout en conservant les comptes additionnels résolus et les privilèges attendus/observés ;
- aucune matérialisation Vote ajoutée : les événements restent des observations structurées et les transactions échouées restent non commitées.
- validation mainnet Vote sur 500 instructions réelles
tower_sync, sans échec Vote ; - correction du seul échec de replay observé, un
set_compute_unit_limitde 12 octets accepté par Agave mais auparavant rejeté par le décodeur strict ; - décodage des dix-huit variantes
StakeInstructiondepuissolana-stake-interface ^4.3, au moyen d’un miroir wire privé compatible avec le format historique et décodé parwincode::deserialize_exact; - distinction entre les layouts de comptes historiques avec sysvars et les layouts BPF modernes, avec
accountLayout, comptes additionnels et privilèges attendus/observés ; - classification de
Redelegatecomme instruction historique officiellement désactivée et décodage des transactions échouées comme intentions non commitées ; - absence de matérialisation Stake tant que l’état préalable du compte, le lockup et la délégation ne sont pas disponibles dans un contrat de projection stable.
- contrat core contextualisé
2, avec accès stable aux payloads de toutes les instructions outer de la transaction ; - décodage structurel exact des précompiles Ed25519, secp256k1 et secp256r1, y compris références courantes/externes, signatures multiples, clé ou adresse, recovery ID et message ;
- conservation bornée des composants par longueur, SHA-256 et préfixe hexadécimal, sans recopier les messages et sans recalculer les signatures ;
- interprétation prudente du runtime : acceptation affirmée uniquement pour une transaction réussie, aucune validité cryptographique affirmée pour une transaction échouée ;
- aucune matérialisation des précompiles, avec
materializedOutputs = 0; - décodage des treize instructions ZK ElGamal Proof depuis
solana-zk-elgamal-proof-interface ^0.1et le runtime Agave ; - distinction entre preuve inline et preuve référencée par compte, offset
u32 LE, création optionnelle d’un compte de contexte et fermeture du contexte ; - séparation bornée contexte/corps pour les preuves inline selon les tailles
Podofficielles, avec longueurs, SHA-256 et préfixes limités, sans conserver ni vérifier cryptographiquement la preuve ; - marquage explicite du contenu historique indisponible pour les preuves stockées dans un compte, sans lecture RPC actuelle susceptible de diverger ;
- aucune matérialisation ZK dans
pre.015, avecmaterializedOutputs = 0.
pre.016 décode l’ancien ZK Token Proof Program comme surface historique et couvre ses dix-sept discriminants officiels. Les layouts inline utilisent les tailles Pod de un miroir wire local audité contre solana-zk-token-sdk 3.1.14; les instructions exactes de cinq octets conservent l’offset vers un compte de preuve, sans lire un état RPC actuel. Les gates historiques enable_zk_proof_from_account et enable_zk_transfer_with_fee, les arités de contexte et l’interdiction historique des vérifications inner sont exposées explicitement.
Le runtime Agave v4.1.1 est un stub sans effet. Un payload qui ne correspond pas exactement à un layout historique est donc classé current_runtime_noop_invocation, pas unsupported ou failed. Aucun corpus mainnet n’ayant été trouvé, la validation repose sur les sources officielles et des fixtures synthétiques. Le décodeur ne vérifie aucune preuve, ne lie pas une transaction à une version runtime supposée et ne produit aucune matérialisation.
Matérialisations natives
Le stateless Slashing Program est couvert depuis pre.018 par deux layouts exacts. La preuve duplicate block externe n’est pas relue depuis un état RPC actuel ; le décodeur conserve uniquement les données transactionnelles et la relation avec l’instruction Ed25519 précédente.
La couverture du décodeur est volontairement plus large que celle de chaque matérialiseur spécialisé. ALT, loaders et Feature possèdent des projections lifecycle stables. Les durable nonce accounts System, les comptes de contexte ZK et les rapports Slashing possèdent désormais leurs projections stables. Stake et Vote nécessitent un matérialiseur d’état dédié, kb_materializer_staking, car une instruction seule ne suffit pas toujours à reconstruire l’état antérieur, le lockup, la délégation ou l’autorité effective.
Compute Budget, les précompiles de signature et les preuves ZK sans contexte restent en audit : ils n’introduisent pas à eux seuls un état métier durable, et une projection partielle serait trompeuse. Cette distinction est maintenant suivie explicitement dans le ROADMAP et dans docs/DECODER_MATERIALIZATION_CONTRACTS.md.
Contrat des événements
Chaque observation décodée contient notamment :
eventVersion;- program ID, surface et entry code ;
- signature, slot et chemin outer/inner via
DecodedProtocolEvent; - paramètres numériques sans perte ;
- comptes résolus avec rôle, index, clé et privilèges attendus/observés ;
transactionSucceeded;- hash du payload ;
- preuve indiquant l’interface officielle utilisée.
Une transaction échouée peut produire un événement d’intention décodé, mais observation_committed reste obligatoirement faux.
Règles locales
- Les commentaires de code restent en anglais.
- La documentation Markdown reste en français.
- Les exports publics sont contrôlés depuis
lib.rs. - Aucun discriminant, offset ou ordre de compte ne doit être ajouté sans source officielle vérifiable.
- Les payloads inconnus ou invalides ne doivent jamais provoquer de panic en production.
Précompiles de signature
Ed25519 et secp256r1 utilisent la sentinelle officielle u16::MAX pour référencer le payload de l’instruction cible. secp256k1 n’a pas de sentinelle : chaque index u8 désigne explicitement une instruction outer, et la provenance current_instruction est déduite lorsque cet index égale celui de la cible. Les données après la table d’offsets restent autorisées, car elles peuvent contenir les signatures, clés et messages référencés.
Les règles zéro signature suivent le runtime : Ed25519 accepte exactement deux octets, secp256k1 exactement un octet, et secp256r1 refuse zéro entrée et limite le compteur à huit. Le décodeur ne dépend d’aucune nouvelle crate officielle : les structures publiées documentent le layout, mais le comportement runtime est reproduit par un parseur local borné et aucune opération cryptographique n’est exécutée.
Interfaces et tracing
Le crate privilégie les interfaces officielles étroites : ALT, System, Vote et Loader v3 utilisent leurs enums officielles avec wincode; Stake consomme son interface officielle et un miroir wire privé wincode parce que StakeInstruction ne dérive pas directement les traits Wincode ; Compute Budget s’aligne sur l’interface Borsh et le comportement unchecked du runtime. Config et Loader v2 conservent des parseurs locaux bornés parce que leurs helpers officiels sont uniquement exposés derrière bincode. Loader v4 conserve également un parser local borné : son interface publie l’enum et les comptes, mais ses helpers sont conditionnés par bincode et aucun schéma wincode n’est exposé.
Depuis 0.4.2-pre.020, Loader v3 est désérialisé par wincode::deserialize_exact<UpgradeableLoaderInstruction>. Les tags, champs, booléens optionnels historiques, payloads suffixés et comptes restent couverts par les fixtures de la crate officielle et par les tests négatifs du décodeur.
Le target canonique est kb_decoder_solana_core. Tout statut failed ou unsupported après dispatch émet un événement error contenant signature, slot, chemin, program ID, processor/version, clé d’input, longueur et hash du payload, statut transactionnel et diagnostics bornés. Une transaction on-chain échouée correctement décodée reste un événement valide non commité.
Compatibilité ZK Token historique sans SDK déprécié
Le crate ne dépend plus de solana-zk-token-sdk. Les tags 0..16, tailles totales de preuve/contexte et règles de forme sont conservés dans une table locale bornée, auditée contre la dernière interface historique et le runtime Agave v2.0.0. Aucun helper bincode n’est utilisé et le fallback no-op Agave v4.1.1 reste explicite.
Matrice de complétude native — 0.4.2-pre.023
docs/NATIVE_SOLANA_DECODER_MATRIX.json inventorie les 18 surfaces de kb_program_ids::native_program_ids() et leurs 121 déclarations de couverture. Le test de matrice impose l’égalité exacte avec SolanaCoreDecoder::surfaces() et SolanaCoreDecoder::coverage(), ainsi que le nombre de déclarations attendu pour chaque Program ID.
La matrice complète les tests spécialisés qui parcourent les enums officielles ou tables wire auditées. Elle empêche qu’une surface soit ajoutée au registre partagé sans décodeur, qu’une famille disparaisse de l’agrégateur ou que son nombre de variantes change sans mise à jour explicite de l’audit.
L’audit consolidé exécuteur/décodeur/RPC est disponible dans docs/SOLANA_NATIVE_RPC_CLOSURE_AUDIT.md.