Files
khadhroony-bot3/docs/NATIVE_SOLANA_PROGRAMS.md
2026-07-23 16:37:12 +02:00

33 KiB
Raw Blame History

Inventaire et couverture des programmes Solana natifs

Périmètre

Le registre kb_program_ids::native_program_ids() contient dix-huit surfaces exécutables : programmes runtime natifs, loaders, précompiles et programmes historiques encore observables. Les sysvars et comptes natifs non exécutables restent suivis séparément dans registry/core_program_id_seed.toml.

Memo ne fait pas partie de ce périmètre. Les IDs officiels v1 Memo1U..., v3 MemoSq... et v4 Memo4c... sont réservés dans kb_decoder_spl_memo.

État du phasage

Phase Contenu État
A modèle dévénement, lecture bornée, validation des comptes et diagnostics implémenté dans 0.4.1-pre.001
B System Program et Compute Budget implémenté, replay mainnet validé dans pre.005
C Address Lookup Table et loaders implémenté dans pre.003 puis pre.006
D Vote, Stake, Config et programmes historiques implémenté : Config/Feature pre.008, Vote pre.010 validé dans pre.011, Stake pre.013 validé mainnet
E précompiles et preuves ZK précompiles signature pre.014, ZK ElGamal Proof pre.015, ancien ZK Token Proof pre.016
F matérialisations justifiées, diagnostics globaux et clôture nonce System/contextes ZK pre.017; Slashing et invariants de couverture pre.018; corpus final à valider

Le processor conserve lidentité solana_native_classifier@0.4.1 pendant les deltas préparatoires. Les nouveaux décodeurs nécessitent donc un force replay ciblé ou global ; la version ne sera relevée quavec un changement explicite du contrat de processor.

Sources normatives couvertes

Surface Source officielle Sérialisation retenue Couverture
System Program solana-system-interface 3.2.0, enum SystemInstruction schéma wincode officiel compatible avec le format bincode historique, lecture exacte sans octets suffixes 14 variantes
Compute Budget actuel solana-compute-budget-interface 3.0.0 + runtime solana-compute-budget-instruction 4.1.1 tag u8 puis entier little-endian/Borsh ; désérialisation runtime unchecked, suffixe accepté et audité 5 entrées, dont le tag réservé Unused
Compute Budget historique ancien solana-sdk, RequestUnitsDeprecated tag 0, u32 units, u32 additional_fee 1 variante historique
Address Lookup Table solana-address-lookup-table-interface 3.1.0, enum ProgramInstruction schéma wincode officiel, lecture exacte 5 variantes
BPF Loader immuable solana-loader-v2-interface 3.0.0, enum LoaderInstruction tag u32 LE, offset u32, longueur de vector u64, lecture exacte write, finalize sur deux générations
BPF Loader upgradeable solana-loader-v3-interface 8.0.1, enum UpgradeableLoaderInstruction wire format historique compatible bincode, champs booléens suffixes avec valeurs historiques documentées 8 variantes
Loader v4 solana-loader-v4-interface 3.1.0, enum LoaderV4Instruction tag et entiers little-endian, tailles exactes 7 variantes
Config Program solana-config-interface 2.0.0 et processor solana-config-program 2.2.20 ConfigKeys en solana_short_vec, clés (Pubkey, bool), puis payload typé opaque pour le décodeur générique 1 écriture générique store
Feature Gate solana-feature-gate-interface 4.0.0, FeatureGateInstruction tag u8 exact 0, sans suffixe 1 variante
Vote Program solana-vote-interface ^6.0, enum VoteInstruction schéma officiel wincode, discriminant historique u32 LE, lecture exacte sans octets suffixes 20 variantes
Stake Program solana-stake-interface ^4.3, enum StakeInstruction miroir wire privé wincode exact du layout historique ; types sémantiques officiels consommés 18 variantes
ZK ElGamal Proof solana-zk-elgamal-proof-interface ^0.1, ProofInstruction, types Pod, runtime Agave tag u8; preuve inline de taille officielle ou référence compte u32 LE sur instruction exacte de 5 octets 13 variantes
ZK Token Proof historique miroir wire local audité contre solana-zk-token-sdk 3.1.14, Agave v2.0.0/v4.1.1 tag u8; layout historique inline ou offset compte sur 5 octets ; fallback runtime actuel sans effet 17 variantes + fallback no-op
Slashing stateless Agave v4.1.1 + solana-program/slashing@fe8da3a tag u8; fermeture sur 1 octet ou preuve duplicate block sur 305 octets exacts 2 variantes

Les versions de crates sont utilisées comme références reproductibles. Un futur changement dinterface doit entraîner un changement de version du décodeur et un replay ledger/version/hash.

System Program

Program ID : 11111111111111111111111111111111.

Tag historique compatible bincode/wincode u32 LE Entry code Paramètres structurés Comptes principaux État
0 create_account lamports, space, owner funding, new account décodé
1 assign owner assigned account décodé
2 transfer lamports funding, recipient décodé
3 create_account_with_seed base, seed, lamports, space, owner funding, new account, base optionnelle décodé
4 advance_nonce_account aucun nonce, recent blockhashes, authority décodé
5 withdraw_nonce_account lamports nonce, recipient, sysvars, authority décodé
6 initialize_nonce_account authority nonce, recent blockhashes, rent décodé
7 authorize_nonce_account authority nonce, authority décodé
8 allocate space allocated account décodé
9 allocate_with_seed base, seed, space, owner derived account, base décodé
10 assign_with_seed base, seed, owner derived account, base décodé
11 transfer_with_seed lamports, from seed, from owner funding, base, recipient décodé
12 upgrade_nonce_account aucun nonce account décodé
13 create_account_allow_prefund lamports, space, owner new account, funding conditionnel décodé

Le décodeur utilise le schéma wincode dérivé directement par solana-system-interface 3.2.0. wincode::deserialize_exact conserve la compatibilité octet pour octet avec le format historique de cette enum et refuse les octets suffixes. Le crate nutilise aucune dépendance directe à bincode.

pre.017 matérialise les cinq opérations durable nonce sous durable_nonce_account:<operation>:0. Initialize, advance, authorize et upgrade conservent leur transition explicite. Withdraw conserve le montant demandé et la règle officielle de fermeture conditionnelle : le compte nest détruit que lorsque la totalité de son solde est retirée. La projection ne prétend pas reconstruire létat final transactionnel du compte et ne duplique pas les deltas SOL du graphe core.

Les flags signer/writable sont conservés sous deux formes : privilèges attendus par le contrat officiel et privilèges réellement résolus depuis core. Ils ne sont pas confondus, car une CPI signée par PDA ne se reflète pas nécessairement comme signer statique de la transaction.

Compute Budget

Program ID : ComputeBudget111111111111111111111111111111.

Tag u8 Entry code Taille décodée minimale Paramètres Statut
0 unused_reserved 1 aucun ignored
0 request_units_deprecated 9 units, additional fee decoded, historique
1 request_heap_frame 5 bytes u32 decoded
2 set_compute_unit_limit 5 compute unit limit u32 decoded
3 set_compute_unit_price 9 micro-lamports u64 decoded
4 set_loaded_accounts_data_size_limit 5 bytes u32 decoded

Le runtime Agave traite les variantes modernes avec solana_borsh::v1::try_from_slice_unchecked. Les octets suffixes sont donc acceptés après les 5 ou 9 octets utiles. Le décodeur reproduit cette règle et conserve trailingDataByteLength, trailingDataSha256, trailingDataPrefixHex et trailingDataSemantics = ignored_by_runtime_borsh_unchecked. Les payloads trop courts restent failed. Le tag 0 demeure dispatché par taille afin de distinguer le tag réservé actuel de la variante historique à neuf octets ; toute autre taille pour ce tag reste failed. Un tag inconnu est unsupported avec diagnostic borné et hash du payload disponible pour un replay futur.

Address Lookup Table

Program ID : AddressLookupTab1e1111111111111111111111111.

Tag u32 LE Entry code Paramètres Comptes État
0 create_lookup_table recent slot, bump seed, politique historique du signer authority table, authority, payer, System Program décodé
1 freeze_lookup_table aucun table, authority décodé
2 extend_lookup_table adresses ajoutées, count, présence du financement table, authority, paire optionnelle payer/System décodé
3 deactivate_lookup_table aucun table, authority décodé
4 close_lookup_table aucun table, authority, recipient décodé

Le décodeur refuse une paire optionnelle dextension incomplète et les octets suffixes. La création conserve expectedSigner = null pour lautorité, car lencodeur officiel actuel ne la marque plus signer tandis que les runtimes historiques antérieurs à v1.12 lexigeaient.

La projection solana_native_lifecycle produit une sortie address_lookup_table:<operation>:0 uniquement si lobservation est exacte, réussie et commitée. Les intentions issues de transactions échouées restent dans decode et sont refusées avant matérialisation.

Programmes runtime natifs principaux

Code canonique Program ID État au début de pre.018
vote Vote111111111111111111111111111111111111111 20 variantes décodées ; 500 tower_sync validés mainnet
stake Stake11111111111111111111111111111111111111 18 variantes décodées ; 339 instructions mainnet sur neuf entry codes observés
config Config1111111111111111111111111111111111111 écriture générique store décodée ; corpus ciblé à inventorier
zk_elgamal_proof ZkE1Gama1Proof11111111111111111111111111111 13 variantes ; 151 instructions mainnet et 139 contextes matérialisés

Loaders

Surface Program ID Variantes Statut pre.006
Native Loader NativeLoader1111111111111111111111111111111 invocation directe opaque ignored, historique, aucun faux événement
BPF Loader deprecated BPFLoader1111111111111111111111111111111111 write, finalize décodé
BPF Loader v2 BPFLoader2111111111111111111111111111111111 write, finalize décodé
BPF Loader upgradeable BPFLoaderUpgradeab1e11111111111111111111111 initialize buffer, write, deploy with max data length, upgrade, set authority, close, extend program, set authority checked décodé
Loader v4 LoaderV411111111111111111111111111111111111 write, copy, set program length, deploy, retract, transfer authority, finalize décodé

Les payloads write ne recopient pas le bytecode dans lévénement : ils conservent offset, longueur et SHA-256. Les tailles de vectors, booléens, octets suffixes et paires de comptes optionnelles sont validés avant toute lecture. Les anciennes formes upgradeable sans le booléen suffixe sont acceptées avec la valeur par défaut officielle et marquées comme telles.

La projection lifecycle produit program_loader:<surface>:<operation>:0 pour les mutations réussies et commitées : finalize immuable, initialize/deploy/upgrade/close/extend upgradeable, puis set length/deploy/retract/finalize v4. Les écritures, copies et changements dautorité restent des événements decode de familles Audit ou Admin.

Slashing Program stateless

Program ID : S1ashing11111111111111111111111111111111111.

Agave v4.1.1 le déclare comme stateless builtin derrière enshrine_slashing_program, avec un hash de build vérifié correspondant à la release officielle solana-program/slashing@fe8da3a.

Tag u8 Entry code Taille exacte Effet runtime observé
0 close_violation_report 1 ferme le rapport après au moins trois epochs et transfère ses lamports
1 duplicate_block_proof 305 vérifie une preuve externe puis stocke un rapport de violation

La preuve duplicate block est lue depuis un compte externe à loffset u64 de linstruction. Le replay transactionnel ne possède pas le contenu historique de ce compte. Le décodeur conserve loffset, le slot, les clés, racines et signatures intégrées à linstruction, résume linstruction Ed25519 précédente et ne prétend ni relire le compte ni recalculer les signatures.

Une transaction réussie prouve seulement lacceptation runtime, lassignation/allocation du PDA préfinancé et lécriture du rapport. Le programme ne brûle ni ne retire lui-même du stake : la projection slashing_violation_report conserve donc penaltyAppliedByProgram = false et décrit un signal destiné à une application de pénalité externe au programme.

Précompiles de signature pre.014

Code canonique Program ID Format État pre.014
ed25519 Ed25519SigVerify111111111111111111111111111 header 2 octets, offsets 14 octets, clé 32, signature 64 décodé, zéro signature accepté seulement sur 2 octets
secp256k1 KeccakSecp256k11111111111111111111111111111 header 1 octet, offsets 11 octets, adresse 20, signature 64 + recovery ID décodé, index u8 explicites, zéro signature accepté seulement sur 1 octet
secp256r1 Secp256r1SigVerify1111111111111111111111111 header 2 octets, offsets 14 octets, clé compressée 33, signature 64 décodé, zéro signature refusé, maximum 8

Le contrat core 2 fournit les payloads de toutes les instructions outer. Ed25519 et secp256r1 interprètent u16::MAX comme la cible ; secp256k1 résout toujours un index explicite. Les références aux inner instructions ne sont pas autorisées. Les offsets et longueurs utilisent des additions vérifiées avant chaque slice.

Chaque observation conserve les index bruts et résolus, la provenance, les longueurs, SHA-256 et préfixes bornés des composants, ainsi que runtimeVerification. Aucun message complet nest recopié, aucune signature nest recalculée et aucune sortie métier nest matérialisée. Une transaction échouée reste decoded si le layout est valide, mais porte not_asserted_transaction_failed et reste non commitée.

Surfaces historiques ou complémentaires

Code canonique Program ID État après pre.008
feature Feature111111111111111111111111111111111111 revoke_pending_activation décodé et lifecycle matérialisable
zk_token_proof ZkTokenProof1111111111111111111111111111111 17 layouts historiques décodés + fallback current_runtime_noop_invocation; validation synthétique

Ancien ZK Token Proof Program

pre.016 couvre les discriminants 0..16 de linterface historique : fermeture du contexte, zero balance, withdraw, égalités de ciphertext/commitment, transfer, transfer with fee, validité de pubkey, range proofs simples et batchés, validité de grouped ciphertext à deux ou trois handles et fee sigma. Les tailles de preuve et de contexte sont maintenant conservées dans une table locale auditée contre les types Pod de solana-zk-token-sdk 3.1.14, sans dépendre de cette crate dépréciée.

Le runtime historique Agave v2.0.0 distinguait une preuve inline dune preuve stockée dans le premier compte lorsque linstruction faisait exactement cinq octets. Il imposait des arités distinctes pour le contexte, refusait les vérifications comme inner instructions et plaçait certains chemins derrière enable_zk_proof_from_account ou enable_zk_transfer_with_fee. Le runtime Agave v4.1.1 est au contraire un stub qui retourne succès sans mutation. Le décodeur conserve ces deux références sans prétendre connaître la version runtime dune transaction donnée.

Aucune signature mainnet na été trouvée pour ce program ID lors du jalon. La surface est donc validée par fixtures synthétiques et sources officielles, sans critère de backfill. Les preuves inline sont seulement mesurées, hashées et préfixées de façon bornée ; les preuves externes conservent loffset et la taille attendue. Aucune preuve nest recalculée et aucune sortie nest matérialisée.

Stake Program

pre.013 couvre les dix-huit variantes de StakeInstruction, tags u32 LE 0..17 : initialize, authorize, delegate, split, withdraw, deactivate, set lockup, merge, autorisations avec seed, variantes checked, minimum delegation, deactivate delinquent, redelegate, move stake et move lamports. Redelegate reste déclaré historique : le processor actuel renvoie InvalidInstructionData avant tout traitement de comptes ; une occurrence réelle doit donc provenir dune transaction échouée et reste non commitée.

Lenum officielle de solana-stake-interface ^4.3 conserve le contrat Serde/Bincode historique, mais nimplémente pas directement SchemaRead/SchemaWrite. Pour respecter linterdiction workspace de dépendre de bincode, le décodeur utilise un miroir wire privé, ordonné exactement comme lenum officielle, décodé par wincode::deserialize_exact. Les tests vérifient manuellement les tags, pubkeys, entiers, enums imbriquées et longueurs de chaînes du layout historique. Les types sémantiques et le program ID officiels restent consommés depuis linterface.

Le processor BPF actuel supporte deux familles de comptes. Les layouts historiques sont détectés par la première sysvar héritée, généralement Clock ou Rent ; les layouts modernes retirent ces sysvars et placent directement les autorités aux positions attendues. Split, SetLockup et SetLockupChecked conservent volontairement les contraintes historiques plus souples du runtime. Le décodeur expose accountLayout, conserve les comptes additionnels et les privilèges attendus/observés, mais ne prétend pas rejouer les vérifications dépendant de létat du stake account, du lockup, de la délégation ou des sysvars courantes. Aucune matérialisation Stake nest ajoutée dans ce delta.

Compte Stake Config historique

StakeConfig11111111111111111111111111111111 nest pas un programme exécutable. Linterface Stake officielle le déclare comme identifiant déprécié du compte de configuration historique du Stake Program. Il reste dans kb_program_ids comme STAKE_CONFIG_ACCOUNT_ID et dans le registre core avec identifier_kind = well_known_account, mais il est exclu des surfaces du décodeur et de lexécuteur.

Config Program

Le Config Program ne possède pas un enum dinstructions discriminé comparable à System ou Stake. Chaque invocation stocke un préfixe ConfigKeys sérialisé avec solana_short_vec, suivi dun payload spécifique au type de configuration. Le décodeur valide la longueur compacte, les clés, les booléens signataires et lordre des comptes signataires, puis conserve le reste par taille, préfixe borné et SHA-256 avec la sémantique explicite opaque_program_specific.

Vote Program

pre.010 utilise solana-vote-interface ^6.0 avec les features serde et wincode. Le discriminant wire historique reste un u32 little-endian compris entre 0 et 19, et wincode::deserialize_exact rejette les octets résiduels. VoteInitV2 contient les autorités, la clé BLS, sa preuve de possession et les deux commissions en points de base ; les collecteurs Inflation Rewards et Block Revenue sont les comptes dinstruction 2 et 3.

La couverture comprend : initialisations V1/V2, autorisations simples/checked/seed, vote et vote switch, mises à jour détat normales/compactes, tower sync, retrait, identité, commissions historiques et en points de base, collecteurs différenciés et dépôt de récompenses délégateurs. Les tableaux BLS V2 sont conservés en hexadécimal exact. Les sysvars Rent, Clock et Slot Hashes sont vérifiées aux positions imposées par linterface. Les privilèges attendus et observés restent distincts afin de ne pas confondre les signataires statiques et les signatures PDA de CPI.

Aucune projection matérialisée spécifique à Vote nest ajoutée dans ce delta : la mutation réelle dépend de létat du vote account et du runtime. Une transaction échouée produit uniquement une observation non commitée.

ZK ElGamal Proof pre.015

Program ID : ZkE1Gama1Proof11111111111111111111111111111.

Le décodeur consomme solana-zk-elgamal-proof-interface ^0.1 pour lenum ProofInstruction et les tailles exactes des types Pod. Il couvre CloseContextState et les douze preuves : zero ciphertext, égalités ciphertext/ciphertext et ciphertext/commitment, validité de clé publique, percentage with cap, range proofs 64/128/256 bits et validités grouped/batched à deux ou trois handles.

Deux modes de transport sont distingués conformément au runtime :

  • instruction de cinq octets : tag puis offset u32 LE vers un compte contenant la preuve ;
  • autre taille exacte : preuve inline immédiatement après le tag, avec taille égale au type ProofData officiel.

Pour une preuve inline, les blocs contexte et preuve sont séparés par leurs tailles Pod, puis conservés uniquement sous forme de longueur, SHA-256 et préfixe hexadécimal borné. Le décodeur ne recalcule aucune preuve cryptographique. Pour une transaction réussie, il indique seulement que linstruction a été acceptée par le runtime. Pour une transaction échouée, aucune validité nest affirmée et lobservation reste non commitée.

Le mode référencé par compte a une limite historique structurelle : le graphe core de transaction ne contient pas le contenu du compte à linstant dexécution. Lévénement conserve donc le compte source, loffset, le type et la taille attendue, mais marque les octets de preuve comme indisponibles. Il ne tente ni lecture RPC actuelle, qui pourrait être divergente, ni reconstruction.

Les comptes optionnels de contexte sont résolus selon le mode : positions 0/1 pour une preuve inline et 1/2 après le compte de preuve pour une preuve externe. La fermeture du contexte conserve le contexte, la destination des lamports et lautorité signataire, accepte les octets suffixes comme le runtime et refuse que contexte et destination désignent le même compte.

pre.017 matérialise le lifecycle du compte de contexte sous zk_proof_context:<operation>:0. Une vérification nest éligible que lorsque contextStateRequested = true, que la transaction a réussi et que lobservation est commitée. La sortie conserve le compte, lautorité et le type de preuve, mais jamais la preuve elle-même. La fermeture réussie décrit la récupération des lamports, la remise à zéro des données et le retour de lowner au System Program. Les preuves sans contexte restent en decode/audit.

Statuts et politique déchec

  • decoded signifie que le format complet a été validé et quune observation structurée a été produite.
  • ignored est réservé à une entrée comprise mais sans événement utile, comme le tag Compute Budget Unused.
  • unsupported conserve une variante inconnue ou une surface non encore implémentée sans faux événement.
  • failed indique un payload absent, invalide, tronqué, non canonique ou des comptes incohérents.
  • unmatched reste un défaut de dispatch et ne doit pas apparaître pour une sélection bornée aux surfaces déclarées.

Une transaction on-chain échouée reste décodable comme intention. Lobservation porte transactionSucceeded = false et observation_committed = false. Le matérialiseur solana_native_lifecycle est actif pour ALT, les mutations loader listées, Feature Gate, les durable nonce accounts System et les comptes de contexte ZK ElGamal. Il accepte les familles Lifecycle, Admin et Audit uniquement au niveau exact surface/entrée/paramètres, puis applique SuccessfulCommittedOnly. Une observation non commitée est refusée et une preuve ZK sans contexte est exclue avant ledger et politique.

Validation mainnet pre.005

Les correctifs de pre.005 ont été validés par les tests ciblés, cargo clippy --all-targets et deux campagnes Tauri. Le force replay ciblé a décodé 3/3 inputs sans échec. Le replay global a sélectionné, démarré et terminé 476 inputs : 476 décodés, zéro failed, unsupported, unmatched et zéro faux materializationRefused. Aucun output nétait attendu, car le corpus ne contenait pas dopération ALT éligible.

Validation pre.006, pre.008, Vote mainnet et anomalie Compute Budget

Les tests pre.006, Clippy et le replay Tauri global ont été validés : 476 inputs sélectionnés, 476 décodés, aucun échec, unsupported, unmatched ou refus de matérialisation. Les validations utilisateur de pre.008 couvrent 256 tests ciblés, PostgreSQL réel, Clippy et un démarrage/replay Tauri propre. Le corpus initial ne contenait que System et Compute Budget : loaders, Config et Feature restent en attente dun corpus réel.

Le backfill Vote de 500 signatures a inséré 500 transactions et lextraction core a terminé 500/500 sans échec. Le replay global suivant contient 500 instructions Vote réelles, toutes reconnues et décodées comme tower_sync, sans échec Vote. Lunique failed de la campagne provient dun set_compute_unit_limit de 12 octets : le runtime laccepte grâce à la désérialisation Borsh unchecked, alors que le décodeur strict exigeait encore 5 octets exacts. pre.011 corrige cet écart. Le processor reste solana_native_classifier@0.4.1 : un force replay est requis pour remplacer le résultat failed déjà enregistré.