v0.1.0-pre.008

This commit is contained in:
2026-07-23 20:40:38 +02:00
parent f5bd8fab7f
commit 12b42a31b8
26 changed files with 6686 additions and 280 deletions

View File

@@ -1,5 +1,5 @@
<!-- file: README.md -->
<!-- version: 4 -->
<!-- version: 5 -->
# Khadhroony Bot3
@@ -53,4 +53,6 @@ cargo clippy --workspace --all-targets
## Décodeurs consolidés
`0.1.0-pre.004` porte le décodeur Solana Core dans `kb-lib`. `0.1.0-pre.005` ajoute SPL Memo v1, v3 et v4. `0.1.0-pre.006` ajoute le décodeur SPL Token classique avec ses 28 tags publiés, son wire borné, ses formes dautorité et son `Batch` structuré. `0.1.0-pre.007` ajoute le programme SPL Associated Token Account avec ses trois instructions, sa forme historique `Create` vide et la validation canonique des PDA pour SPL Token classique et Token2022. Tous utilisent les mêmes contrats contextualisés, la même façade publique et aucune dépendance inverse vers `kb-store`.
`0.1.0-pre.004` porte le décodeur Solana Core dans `kb-lib`. `0.1.0-pre.005` ajoute SPL Memo v1, v3 et v4. `0.1.0-pre.006` ajoute le décodeur SPL Token classique avec ses 28 tags publiés, son wire borné, ses formes dautorité et son `Batch` structuré. `0.1.0-pre.007` ajoute le programme SPL Associated Token Account avec ses trois instructions, sa forme historique `Create` vide et la validation canonique des PDA pour SPL Token classique et Token2022.
`0.1.0-pre.008` porte le décodeur Token2022 maximal, son parseur détats Mint/Account/Multisig et de TLV, ainsi que le programme indépendant du registre ElGamal. Les deux composants gardent des frontières et des targets de tracing distincts. Tous les décodeurs migrés utilisent les mêmes contrats contextualisés, la même façade publique et aucune dépendance inverse vers `kb-store`.

View File

@@ -1,5 +1,5 @@
<!-- file: ROADMAP.md -->
<!-- version: 5 -->
<!-- version: 6 -->
# ROADMAP — khadhroony-bot3
@@ -83,5 +83,18 @@
- [x] Distinguer explicitement SPL Token classique et Token2022 sans décoder leurs états ni extensions.
- [x] Conserver les dix tests différentiels et la matrice machine-readable ATA.
- [x] Porter le target de tracing vers `kb-lib.decoder.spl.associated_token_account`.
- [ ] Valider `kb-program-ids`, les 196 tests de `kb-lib`, Clippy et le workspace avec Cargo sur la machine de développement.
- [ ] Poursuivre avec les décodeurs Token2022 et registre ElGamal après validation.
- [x] Valider `kb-program-ids`, les 196 tests de `kb-lib`, Clippy et le workspace avec Cargo sur la machine de développement.
- [x] Poursuivre avec les décodeurs Token2022 et registre ElGamal après validation.
### 0.1.0-pre.008 — Décodeurs Token2022 et registre ElGamal dans `kb-lib`
- [x] Remplacer les scaffolds `token_2022` et `elgamal_registry` par les décodeurs exacts validés de bot2.
- [x] Conserver les 48 enveloppes Token2022, les sous-instructions dextensions identifiables et les interfaces Metadata/Group incorporées.
- [x] Porter le parseur borné des états Mint, Account et Multisig avec leurs entrées TLV ordonnées.
- [x] Maintenir le registre ElGamal comme programme indépendant avec ses deux instructions et son état de compte exact de 64 octets.
- [x] Ajouter le Program ID du registre ElGamal à `kb-program-ids` sans le classer comme surface native.
- [x] Déplacer `ProgramIdEntry` et les fonctions du registre dans `kb-program-ids/src/programs.rs`, avec `lib.rs` limité aux réexports.
- [x] Porter les targets de tracing vers `kb-lib.decoder.spl.token_2022` et `kb-lib.decoder.spl.elgamal_registry`.
- [x] Conserver les 55 tests Token2022/ElGamal et leurs matrices machine-readable.
- [ ] Valider `kb-program-ids`, les 251 tests de `kb-lib`, Clippy et le workspace avec Cargo sur la machine de développement.
- [ ] Poursuivre avec le décodeur Metaplex Token Metadata après validation.

View File

@@ -25,10 +25,10 @@
"kb_decoder_metadata_metaplex_token_metadata",
"kb-lib.decoder.solana.core",
"kb-lib.decoder.spl.associated_token_account",
"kb_decoder_spl_elgamal_registry",
"kb-lib.decoder.spl.elgamal_registry",
"kb-lib.decoder.spl.memo",
"kb-lib.decoder.spl.token",
"kb_decoder_spl_token_2022",
"kb-lib.decoder.spl.token_2022",
"kb_execution_solana",
"kb_executor_metadata_metaplex_token_metadata",
"kb_executor_metadata_spl_name_service",
@@ -1122,42 +1122,42 @@
]
},
{
"name": "file_kb_decoder_spl_token_2022_debug",
"name": "file_kb_lib_decoder_spl_token_2022_debug",
"enabled": true,
"sink": "file",
"level": "debug",
"path": "logs/devnet/kb_decoder_spl_token_2022/debug.log",
"path": "logs/devnet/kb_lib_decoder_spl_token_2022/debug.log",
"rotation": "daily",
"format": "human",
"ansi": false,
"targets": [
"kb_decoder_spl_token_2022"
"kb-lib.decoder.spl.token_2022"
]
},
{
"name": "file_kb_decoder_spl_token_2022_info",
"name": "file_kb_lib_decoder_spl_token_2022_info",
"enabled": true,
"sink": "file",
"level": "info",
"path": "logs/devnet/kb_decoder_spl_token_2022/info.log",
"path": "logs/devnet/kb_lib_decoder_spl_token_2022/info.log",
"rotation": "daily",
"format": "human",
"ansi": false,
"targets": [
"kb_decoder_spl_token_2022"
"kb-lib.decoder.spl.token_2022"
]
},
{
"name": "file_kb_decoder_spl_token_2022_error",
"name": "file_kb_lib_decoder_spl_token_2022_error",
"enabled": true,
"sink": "file",
"level": "error",
"path": "logs/devnet/kb_decoder_spl_token_2022/error.jsonl",
"path": "logs/devnet/kb_lib_decoder_spl_token_2022/error.jsonl",
"rotation": "daily",
"format": "json",
"ansi": false,
"targets": [
"kb_decoder_spl_token_2022"
"kb-lib.decoder.spl.token_2022"
]
},
{
@@ -1200,42 +1200,42 @@
]
},
{
"name": "file_kb_decoder_spl_elgamal_registry_debug",
"name": "file_kb_lib_decoder_spl_elgamal_registry_debug",
"enabled": true,
"sink": "file",
"level": "debug",
"path": "logs/devnet/kb_decoder_spl_elgamal_registry/debug.log",
"path": "logs/devnet/kb_lib_decoder_spl_elgamal_registry/debug.log",
"rotation": "daily",
"format": "human",
"ansi": false,
"targets": [
"kb_decoder_spl_elgamal_registry"
"kb-lib.decoder.spl.elgamal_registry"
]
},
{
"name": "file_kb_decoder_spl_elgamal_registry_info",
"name": "file_kb_lib_decoder_spl_elgamal_registry_info",
"enabled": true,
"sink": "file",
"level": "info",
"path": "logs/devnet/kb_decoder_spl_elgamal_registry/info.log",
"path": "logs/devnet/kb_lib_decoder_spl_elgamal_registry/info.log",
"rotation": "daily",
"format": "human",
"ansi": false,
"targets": [
"kb_decoder_spl_elgamal_registry"
"kb-lib.decoder.spl.elgamal_registry"
]
},
{
"name": "file_kb_decoder_spl_elgamal_registry_error",
"name": "file_kb_lib_decoder_spl_elgamal_registry_error",
"enabled": true,
"sink": "file",
"level": "error",
"path": "logs/devnet/kb_decoder_spl_elgamal_registry/error.jsonl",
"path": "logs/devnet/kb_lib_decoder_spl_elgamal_registry/error.jsonl",
"rotation": "daily",
"format": "json",
"ansi": false,
"targets": [
"kb_decoder_spl_elgamal_registry"
"kb-lib.decoder.spl.elgamal_registry"
]
},
{
@@ -1627,10 +1627,10 @@
"kb_decoder_metadata_metaplex_token_metadata",
"kb-lib.decoder.solana.core",
"kb-lib.decoder.spl.associated_token_account",
"kb_decoder_spl_elgamal_registry",
"kb-lib.decoder.spl.elgamal_registry",
"kb-lib.decoder.spl.memo",
"kb-lib.decoder.spl.token",
"kb_decoder_spl_token_2022",
"kb-lib.decoder.spl.token_2022",
"kb_execution_solana",
"kb_executor_metadata_metaplex_token_metadata",
"kb_executor_metadata_spl_name_service",
@@ -2724,42 +2724,42 @@
]
},
{
"name": "file_kb_decoder_spl_token_2022_debug",
"name": "file_kb_lib_decoder_spl_token_2022_debug",
"enabled": true,
"sink": "file",
"level": "debug",
"path": "logs/mainnet_research/kb_decoder_spl_token_2022/debug.log",
"path": "logs/mainnet_research/kb_lib_decoder_spl_token_2022/debug.log",
"rotation": "daily",
"format": "human",
"ansi": false,
"targets": [
"kb_decoder_spl_token_2022"
"kb-lib.decoder.spl.token_2022"
]
},
{
"name": "file_kb_decoder_spl_token_2022_info",
"name": "file_kb_lib_decoder_spl_token_2022_info",
"enabled": true,
"sink": "file",
"level": "info",
"path": "logs/mainnet_research/kb_decoder_spl_token_2022/info.log",
"path": "logs/mainnet_research/kb_lib_decoder_spl_token_2022/info.log",
"rotation": "daily",
"format": "human",
"ansi": false,
"targets": [
"kb_decoder_spl_token_2022"
"kb-lib.decoder.spl.token_2022"
]
},
{
"name": "file_kb_decoder_spl_token_2022_error",
"name": "file_kb_lib_decoder_spl_token_2022_error",
"enabled": true,
"sink": "file",
"level": "error",
"path": "logs/mainnet_research/kb_decoder_spl_token_2022/error.jsonl",
"path": "logs/mainnet_research/kb_lib_decoder_spl_token_2022/error.jsonl",
"rotation": "daily",
"format": "json",
"ansi": false,
"targets": [
"kb_decoder_spl_token_2022"
"kb-lib.decoder.spl.token_2022"
]
},
{
@@ -2802,42 +2802,42 @@
]
},
{
"name": "file_kb_decoder_spl_elgamal_registry_debug",
"name": "file_kb_lib_decoder_spl_elgamal_registry_debug",
"enabled": true,
"sink": "file",
"level": "debug",
"path": "logs/mainnet_research/kb_decoder_spl_elgamal_registry/debug.log",
"path": "logs/mainnet_research/kb_lib_decoder_spl_elgamal_registry/debug.log",
"rotation": "daily",
"format": "human",
"ansi": false,
"targets": [
"kb_decoder_spl_elgamal_registry"
"kb-lib.decoder.spl.elgamal_registry"
]
},
{
"name": "file_kb_decoder_spl_elgamal_registry_info",
"name": "file_kb_lib_decoder_spl_elgamal_registry_info",
"enabled": true,
"sink": "file",
"level": "info",
"path": "logs/mainnet_research/kb_decoder_spl_elgamal_registry/info.log",
"path": "logs/mainnet_research/kb_lib_decoder_spl_elgamal_registry/info.log",
"rotation": "daily",
"format": "human",
"ansi": false,
"targets": [
"kb_decoder_spl_elgamal_registry"
"kb-lib.decoder.spl.elgamal_registry"
]
},
{
"name": "file_kb_decoder_spl_elgamal_registry_error",
"name": "file_kb_lib_decoder_spl_elgamal_registry_error",
"enabled": true,
"sink": "file",
"level": "error",
"path": "logs/mainnet_research/kb_decoder_spl_elgamal_registry/error.jsonl",
"path": "logs/mainnet_research/kb_lib_decoder_spl_elgamal_registry/error.jsonl",
"rotation": "daily",
"format": "json",
"ansi": false,
"targets": [
"kb_decoder_spl_elgamal_registry"
"kb-lib.decoder.spl.elgamal_registry"
]
},
{
@@ -3429,10 +3429,10 @@
"kb_decoder_metadata_metaplex_token_metadata",
"kb-lib.decoder.solana.core",
"kb-lib.decoder.spl.associated_token_account",
"kb_decoder_spl_elgamal_registry",
"kb-lib.decoder.spl.elgamal_registry",
"kb-lib.decoder.spl.memo",
"kb-lib.decoder.spl.token",
"kb_decoder_spl_token_2022",
"kb-lib.decoder.spl.token_2022",
"kb_execution_solana",
"kb_executor_metadata_metaplex_token_metadata",
"kb_executor_metadata_spl_name_service",
@@ -4526,42 +4526,42 @@
]
},
{
"name": "file_kb_decoder_spl_token_2022_debug",
"name": "file_kb_lib_decoder_spl_token_2022_debug",
"enabled": true,
"sink": "file",
"level": "debug",
"path": "logs/mainnet/kb_decoder_spl_token_2022/debug.log",
"path": "logs/mainnet/kb_lib_decoder_spl_token_2022/debug.log",
"rotation": "daily",
"format": "human",
"ansi": false,
"targets": [
"kb_decoder_spl_token_2022"
"kb-lib.decoder.spl.token_2022"
]
},
{
"name": "file_kb_decoder_spl_token_2022_info",
"name": "file_kb_lib_decoder_spl_token_2022_info",
"enabled": true,
"sink": "file",
"level": "info",
"path": "logs/mainnet/kb_decoder_spl_token_2022/info.log",
"path": "logs/mainnet/kb_lib_decoder_spl_token_2022/info.log",
"rotation": "daily",
"format": "human",
"ansi": false,
"targets": [
"kb_decoder_spl_token_2022"
"kb-lib.decoder.spl.token_2022"
]
},
{
"name": "file_kb_decoder_spl_token_2022_error",
"name": "file_kb_lib_decoder_spl_token_2022_error",
"enabled": true,
"sink": "file",
"level": "error",
"path": "logs/mainnet/kb_decoder_spl_token_2022/error.jsonl",
"path": "logs/mainnet/kb_lib_decoder_spl_token_2022/error.jsonl",
"rotation": "daily",
"format": "json",
"ansi": false,
"targets": [
"kb_decoder_spl_token_2022"
"kb-lib.decoder.spl.token_2022"
]
},
{
@@ -4604,42 +4604,42 @@
]
},
{
"name": "file_kb_decoder_spl_elgamal_registry_debug",
"name": "file_kb_lib_decoder_spl_elgamal_registry_debug",
"enabled": true,
"sink": "file",
"level": "debug",
"path": "logs/mainnet/kb_decoder_spl_elgamal_registry/debug.log",
"path": "logs/mainnet/kb_lib_decoder_spl_elgamal_registry/debug.log",
"rotation": "daily",
"format": "human",
"ansi": false,
"targets": [
"kb_decoder_spl_elgamal_registry"
"kb-lib.decoder.spl.elgamal_registry"
]
},
{
"name": "file_kb_decoder_spl_elgamal_registry_info",
"name": "file_kb_lib_decoder_spl_elgamal_registry_info",
"enabled": true,
"sink": "file",
"level": "info",
"path": "logs/mainnet/kb_decoder_spl_elgamal_registry/info.log",
"path": "logs/mainnet/kb_lib_decoder_spl_elgamal_registry/info.log",
"rotation": "daily",
"format": "human",
"ansi": false,
"targets": [
"kb_decoder_spl_elgamal_registry"
"kb-lib.decoder.spl.elgamal_registry"
]
},
{
"name": "file_kb_decoder_spl_elgamal_registry_error",
"name": "file_kb_lib_decoder_spl_elgamal_registry_error",
"enabled": true,
"sink": "file",
"level": "error",
"path": "logs/mainnet/kb_decoder_spl_elgamal_registry/error.jsonl",
"path": "logs/mainnet/kb_lib_decoder_spl_elgamal_registry/error.jsonl",
"rotation": "daily",
"format": "json",
"ansi": false,
"targets": [
"kb_decoder_spl_elgamal_registry"
"kb-lib.decoder.spl.elgamal_registry"
]
},
{

View File

@@ -1,5 +1,5 @@
<!-- file: docs/SOLANA_INTERFACE_DEPENDENCIES.md -->
<!-- version: 29 -->
<!-- version: 30 -->
# Dépendances dinterfaces Solana et SPL
@@ -182,9 +182,11 @@ instructions et extensions Token-2022 reste réservé à `0.4.6`.
Le catalogue workspace déclare `spl-token-2022-interface ^3.1` avec `serde` et
`spl-elgamal-registry-interface ^0.2` sans feature additionnelle. La résolution opérateur confirme
respectivement `3.1.1` avec `default + serde` et `0.2.1` avec `default`, consommées par
`kb_decoder_spl_token_2022` pour poursuivre l'audit. La matrice inventorie 48 tags de premier
niveau et 29 types TLV de production, dont le récent `PermissionedBurnExtension` `46` et son TLV
respectivement `3.1.1` avec `default + serde` et `0.2.1` avec `default`. Dans bot3, `kb-lib`
les consomme comme dépendances de développement pour les tests différentiels ; le code de
production utilise les parseurs locaux bornés déjà prouvés contre ces interfaces. La matrice
inventorie 48 tags de premier niveau et 29 types TLV de production, dont le récent
`PermissionedBurnExtension` `46` et son TLV
`PermissionedBurn` `28`.
Les sous-discriminants, comptes, layouts, tailles, builders et processors restent explicitement
@@ -211,6 +213,12 @@ ni discriminant, ni builder : elle ajoute seulement, avant Borsh, une validation
longueurs de chaînes de `Initialize`, `UpdateField` et `RemoveKey`. Cette garde plus sûre devient
normative pour le décodeur ; `UpdateAuthority` et `Emit` restent sans chaîne.
La migration `0.1.0-pre.008` conserve ces contrats dans
`kb_lib::decoder::spl::token_2022` et isole le registre dans
`kb_lib::decoder::spl::elgamal_registry`. Les targets de tracing, matrices et Program IDs restent
distincts ; aucun pointeur TLV nest interprété comme une preuve de létat du programme externe
pointé.
### ZK ElGamal Proof
`kb_decoder_solana_core` consomme directement `solana-zk-elgamal-proof-interface ^0.1`. Lenum `ProofInstruction` fournit les treize discriminants et les types de `proof_data` fournissent les tailles `Pod` exactes pour séparer le contexte du corps de preuve inline. Le runtime Agave reste la source normative pour la sélection entre preuve inline et preuve stockée dans un compte, les positions de comptes optionnels et lacceptation des octets suffixes de `CloseContextState`.

View File

@@ -1,6 +1,6 @@
{
"file": "docs/SPL_ELGAMAL_REGISTRY_MATRIX.json",
"version": 1,
"version": "0.1.0-pre.008",
"programId": "regVYJW7tcT8zipN5YiBvHsvR5jXW1uLFxaHSbugABg",
"interface": {
"crate": "spl-elgamal-registry-interface",
@@ -112,7 +112,7 @@
"publishedInlineBuilderOffset": 1
},
"decoder": {
"crate": "kb_decoder_spl_elgamal_registry",
"component": "kb-lib.decoder.spl.elgamal_registry",
"coverageEqualityRequired": true,
"unknownTagPolicy": "failed",
"trailingBytesPolicy": "failed",

View File

@@ -1,6 +1,6 @@
{
"file": "docs/SPL_TOKEN_2022_MATRIX.json",
"version": "0.4.6-pre.026",
"version": "0.1.0-pre.008",
"schemaVersion": 1,
"matrixStatus": "exact_decoder_leaf_coverage_proven_pending_materialization_executor_preflight_and_cluster_corpus_completion",
"programId": "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb",
@@ -30,7 +30,7 @@
"default",
"serde"
],
"leafConsumer": "kb_decoder_spl_token_2022",
"leafConsumer": "kb-lib.decoder.spl.token_2022",
"operatorEvidence": "cargo tree -i spl-token-2022-interface -e features",
"publishedCandidateAudited": "3.1.1",
"publishedCandidateStatus": "matches_confirmed_workspace_resolution",
@@ -66,12 +66,11 @@
"metadataVersionDriftStatus": "unpack_hardening_only_wire_and_builders_unchanged_by_source_diff"
},
"operatorCommandsRequired": [
"cargo tree -p kb_decoder_spl_token_2022 -e features",
"cargo tree -p kb_executor_spl_token_2022 -e features",
"cargo tree -p kb-lib -e features",
"cargo tree -i spl-token-2022-interface -e features",
"cargo tree -i spl-elgamal-registry-interface -e features",
"cargo metadata --format-version 1 --locked",
"cargo test -p kb_decoder_spl_token_2022",
"cargo test -p kb-lib",
"cargo clippy --all-targets"
],
"sourceCommit": "e18f9c6f9bf6044b934f48e3090e8e59e4820f02",
@@ -2079,13 +2078,13 @@
"default"
],
"resolutionStatus": "confirmed_by_operator_cargo_tree_2026-07-16",
"leafConsumer": "kb_decoder_spl_token_2022_for_audit_only_pending_dedicated_crate_decision",
"leafConsumer": "kb-lib.decoder.spl.elgamal_registry",
"operatorEvidence": "cargo tree -i spl-elgamal-registry-interface -e features",
"programId": "regVYJW7tcT8zipN5YiBvHsvR5jXW1uLFxaHSbugABg",
"programIdEvidence": "spl-elgamal-registry-interface 0.2.1 declare_id",
"registryAddressSeedUtf8": "elgamal-registry",
"status": "identity_confirmed_separate_instruction_processor_and_cluster_audit_pending",
"matrix": "separate_matrix_required",
"status": "identity_and_exact_two_instruction_decoder_confirmed_separate_stateful_and_cluster_validation_pending",
"matrix": "docs/SPL_ELGAMAL_REGISTRY_MATRIX.json",
"sharedInstructionEnum": false,
"sharedDecoder": false,
"sharedExecutor": false,

View File

@@ -1,5 +1,5 @@
<!-- file: docs/TRACING_CONTRACT.md -->
<!-- version: 16 -->
<!-- version: 17 -->
# Contrat de tracing par crate et composant
@@ -58,8 +58,10 @@ Les targets déjà migrés vers les noms canoniques bot3 sont :
```text
kb-lib.decoder.solana.core
kb-lib.decoder.spl.associated_token_account
kb-lib.decoder.spl.elgamal_registry
kb-lib.decoder.spl.memo
kb-lib.decoder.spl.token
kb-lib.decoder.spl.token_2022
kb-logging
kb-store
```

View File

@@ -1,5 +1,5 @@
# file: kb-lib/Cargo.toml
# version: 6
# version: 7
[package]
name = "kb-lib"
@@ -31,7 +31,9 @@ ts-rs.workspace = true
wincode.workspace = true
[dev-dependencies]
spl-elgamal-registry-interface.workspace = true
spl-memo-interface.workspace = true
spl-token-2022-interface.workspace = true
spl-token-interface.workspace = true
[lints]

View File

@@ -1,5 +1,5 @@
<!-- file: kb-lib/README.md -->
<!-- version: 4 -->
<!-- version: 5 -->
# kb-lib
@@ -56,12 +56,39 @@ puis expose tout écart comme diagnostic. SPL Token classique et Token2022 so
Program ID sans reconstruire leur état ni interpréter leurs extensions. La matrice normative est
`docs/SPL_ASSOCIATED_TOKEN_ACCOUNT_MATRIX.json`.
## Décodeur SPL Token2022
`SplToken2022Decoder` couvre exclusivement
`TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb`. Il conserve les 48 enveloppes de premier niveau,
les sous-instructions dextensions dont le wire est officiellement identifiable, les interfaces
Token Metadata et Token Group exécutées directement par Token2022, ainsi que `Batch` sans batch
imbriqué.
Le décodeur borne les payloads, les chaînes de metadata, le nombre denfants et les comptes
cumulés. Les comptes, autorités, offsets de preuve, suffixes et chemins outer/inner restent
ordonnés et exacts. Une transaction échouée produit une intention non commitée. Le parseur public
`parse_token_2022_state()` distingue Mint, Account et Multisig, conserve la base exacte et expose
les entrées TLV ordonnées sans inventer létat dun programme externe pointé. La matrice normative
est `docs/SPL_TOKEN_2022_MATRIX.json`.
## Décodeur du registre ElGamal
`SplElgamalRegistryDecoder` couvre le programme indépendant
`regVYJW7tcT8zipN5YiBvHsvR5jXW1uLFxaHSbugABg`. Il décode exactement `CreateRegistry` et
`UpdateRegistry`, conserve loffset relatif de preuve et ne prétend jamais vérifier la preuve ZK.
`parse_elgamal_registry_state()` exige exactement 64 octets et restitue le wallet propriétaire, la
clé publique ElGamal et le wire complet. La matrice normative est
`docs/SPL_ELGAMAL_REGISTRY_MATRIX.json`.
## API publique utile
- `SolanaCoreDecoder` : décodeur concret natif ;
- `SplMemoDecoder` : décodeur exact des trois générations SPL Memo ;
- `SplTokenDecoder` : décodeur exact du programme SPL Token classique ;
- `SplAssociatedTokenAccountDecoder` : décodeur exact du programme Associated Token Account ;
- `SplToken2022Decoder` : décodeur exact des instructions Token2022 ;
- `Token2022State`, `Token2022StateKind`, `Token2022TlvEntry` et `parse_token_2022_state()` : API publique de lecture détat Token2022 ;
- `SplElgamalRegistryDecoder`, `ElGamalRegistryState` et `parse_elgamal_registry_state()` : API publique du registre ElGamal ;
- `InstructionDecoder` : contrat de reconnaissance, couverture et décodage contextualisé ;
- `ProtocolDecoder` : contrat de compatibilité avec les observations historiques ;
- `CoreInstructionReplayInput` : input source-neutral produit par lextraction core ;

View File

@@ -1,5 +1,5 @@
// file: kb-lib/src/decoder.rs
// version: 4
// version: 5
//! Consolidated decoder modules.
@@ -33,6 +33,8 @@ pub mod vesting;
pub mod wallet;
pub mod weighted;
/// One parsed SPL ElGamal registry instruction.
pub(crate) use self::spl::ParsedRegistryInstruction;
/// Current stable Associated Token Account decoded event contract version.
pub(crate) use self::spl::SPL_ASSOCIATED_TOKEN_ACCOUNT_EVENT_VERSION;
/// Exact Associated Token Account instructions published by the official interface.
@@ -51,6 +53,14 @@ pub(crate) use self::spl::SPL_ASSOCIATED_TOKEN_ACCOUNT_MAX_TRANSACTION_KEYS;
pub(crate) use self::spl::SPL_ASSOCIATED_TOKEN_ACCOUNT_SURFACE_CODE;
/// Canonical tracing target for the Associated Token Account decoder.
pub(crate) use self::spl::SPL_ASSOCIATED_TOKEN_ACCOUNT_TRACING_TARGET;
/// Current stable SPL ElGamal registry event contract version.
pub(crate) use self::spl::SPL_ELGAMAL_REGISTRY_EVENT_VERSION;
/// Maximum retained SPL ElGamal registry instruction payload size.
pub(crate) use self::spl::SPL_ELGAMAL_REGISTRY_MAX_INSTRUCTION_BYTES;
/// Stable SPL ElGamal registry surface code.
pub(crate) use self::spl::SPL_ELGAMAL_REGISTRY_SURFACE_CODE;
/// Canonical tracing target for the SPL ElGamal registry decoder.
pub(crate) use self::spl::SPL_ELGAMAL_REGISTRY_TRACING_TARGET;
/// Maximum payload prefix retained for bounded diagnostics.
pub(crate) use self::spl::SPL_MEMO_DIAGNOSTIC_PREFIX_BYTES;
/// Current stable Memo decoded event contract version.
@@ -67,6 +77,24 @@ pub(crate) use self::spl::SPL_MEMO_V1_SURFACE_CODE;
pub(crate) use self::spl::SPL_MEMO_V3_SURFACE_CODE;
/// Stable Memo v4 surface code.
pub(crate) use self::spl::SPL_MEMO_V4_SURFACE_CODE;
/// Maximum prefix retained in bounded Token-2022 diagnostics.
pub(crate) use self::spl::SPL_TOKEN_2022_DIAGNOSTIC_PREFIX_BYTES;
/// Current stable Token-2022 decoded event contract version.
pub(crate) use self::spl::SPL_TOKEN_2022_EVENT_VERSION;
/// Exact top-level instruction inventory published by the resolved Token-2022 interface.
pub(crate) use self::spl::SPL_TOKEN_2022_INSTRUCTION_ENTRIES;
/// Maximum total account metas consumed by one Token-2022 batch.
pub(crate) use self::spl::SPL_TOKEN_2022_MAX_BATCH_ACCOUNTS;
/// Maximum decoded sub-instructions in one Token-2022 batch.
pub(crate) use self::spl::SPL_TOKEN_2022_MAX_BATCH_INSTRUCTIONS;
/// Maximum retained Token-2022 instruction payload size.
pub(crate) use self::spl::SPL_TOKEN_2022_MAX_INSTRUCTION_BYTES;
/// Maximum retained UTF-8 string size for embedded Token Metadata instructions.
pub(crate) use self::spl::SPL_TOKEN_2022_MAX_METADATA_STRING_BYTES;
/// Stable Token-2022 surface code.
pub(crate) use self::spl::SPL_TOKEN_2022_SURFACE_CODE;
/// Canonical tracing target for the Token-2022 decoder.
pub(crate) use self::spl::SPL_TOKEN_2022_TRACING_TARGET;
/// Maximum prefix retained in bounded classic SPL Token diagnostics.
pub(crate) use self::spl::SPL_TOKEN_DIAGNOSTIC_PREFIX_BYTES;
/// Current stable classic SPL Token decoded event contract version.
@@ -89,8 +117,20 @@ pub(crate) use self::spl::spl_associated_token_account_decode;
pub(crate) use self::spl::spl_associated_token_account_entry;
/// Reads one bounded Associated Token Account payload.
pub(crate) use self::spl::spl_associated_token_account_payload;
/// Decodes one bounded SPL ElGamal registry instruction.
pub(crate) use self::spl::spl_elgamal_registry_decode;
/// Decodes one bounded SPL ElGamal registry instruction payload.
pub(crate) use self::spl::spl_elgamal_registry_decode_payload;
/// Parses one exact SPL ElGamal registry instruction.
pub(crate) use self::spl::spl_elgamal_registry_parse;
/// Decodes one bounded SPL Memo instruction.
pub(crate) use self::spl::spl_memo_decode;
/// Decodes one bounded Token-2022 instruction.
pub(crate) use self::spl::spl_token_2022_decode;
/// Returns the exact entry matching one Token-2022 tag.
pub(crate) use self::spl::spl_token_2022_entry_for_tag;
/// Returns the first byte of one retained Token-2022 payload.
pub(crate) use self::spl::spl_token_2022_payload_tag;
/// Decodes one bounded classic SPL Token instruction.
pub(crate) use self::spl::spl_token_decode;
/// Returns the published entry matching one classic SPL Token tag.
@@ -98,9 +138,27 @@ pub(crate) use self::spl::spl_token_entry_for_tag;
/// Returns the first byte of one retained classic SPL Token payload.
pub(crate) use self::spl::spl_token_payload_tag;
/// Exact byte length of one SPL ElGamal registry account.
pub use self::spl::ELGAMAL_REGISTRY_ACCOUNT_LEN;
/// Parsed SPL ElGamal public-key registry account.
pub use self::spl::ElGamalRegistryState;
/// Exact decoder for the SPL Associated Token Account program.
pub use self::spl::SplAssociatedTokenAccountDecoder;
/// Exact decoder for the SPL ElGamal registry program.
pub use self::spl::SplElgamalRegistryDecoder;
/// Exact decoder for the three registered SPL Memo generations.
pub use self::spl::SplMemoDecoder;
/// Exact decoder for the Token-2022 program.
pub use self::spl::SplToken2022Decoder;
/// Exact decoder for the classic SPL Token program.
pub use self::spl::SplTokenDecoder;
/// Parsed Token-2022 Mint, Account, or Multisig state.
pub use self::spl::Token2022State;
/// Exact Token-2022 base account state kind.
pub use self::spl::Token2022StateKind;
/// One exact Token-2022 TLV entry.
pub use self::spl::Token2022TlvEntry;
/// Parses one exact SPL ElGamal registry account.
pub use self::spl::parse_elgamal_registry_state;
/// Parses one Token-2022 Mint, Account, or Multisig state.
pub use self::spl::parse_token_2022_state;

View File

@@ -1,5 +1,5 @@
// file: kb-lib/src/decoder/spl.rs
// version: 4
// version: 5
//! `spl` decoder family.
@@ -37,6 +37,22 @@ pub(crate) use self::associated_token_account::spl_associated_token_account_deco
pub(crate) use self::associated_token_account::spl_associated_token_account_entry;
/// Reads one bounded Associated Token Account payload.
pub(crate) use self::associated_token_account::spl_associated_token_account_payload;
/// One parsed SPL ElGamal registry instruction.
pub(crate) use self::elgamal_registry::ParsedRegistryInstruction;
/// Current stable SPL ElGamal registry event contract version.
pub(crate) use self::elgamal_registry::SPL_ELGAMAL_REGISTRY_EVENT_VERSION;
/// Maximum retained SPL ElGamal registry instruction payload size.
pub(crate) use self::elgamal_registry::SPL_ELGAMAL_REGISTRY_MAX_INSTRUCTION_BYTES;
/// Stable SPL ElGamal registry surface code.
pub(crate) use self::elgamal_registry::SPL_ELGAMAL_REGISTRY_SURFACE_CODE;
/// Canonical tracing target for the SPL ElGamal registry decoder.
pub(crate) use self::elgamal_registry::SPL_ELGAMAL_REGISTRY_TRACING_TARGET;
/// Decodes one bounded SPL ElGamal registry instruction.
pub(crate) use self::elgamal_registry::spl_elgamal_registry_decode;
/// Decodes one bounded SPL ElGamal registry instruction payload.
pub(crate) use self::elgamal_registry::spl_elgamal_registry_decode_payload;
/// Parses one exact SPL ElGamal registry instruction.
pub(crate) use self::elgamal_registry::spl_elgamal_registry_parse;
/// Maximum payload prefix retained for bounded diagnostics.
pub(crate) use self::memo::SPL_MEMO_DIAGNOSTIC_PREFIX_BYTES;
/// Current stable Memo decoded event contract version.
@@ -77,10 +93,52 @@ pub(crate) use self::token::spl_token_decode;
pub(crate) use self::token::spl_token_entry_for_tag;
/// Returns the first byte of one retained classic SPL Token payload.
pub(crate) use self::token::spl_token_payload_tag;
/// Maximum prefix retained in bounded Token-2022 diagnostics.
pub(crate) use self::token_2022::SPL_TOKEN_2022_DIAGNOSTIC_PREFIX_BYTES;
/// Current stable Token-2022 decoded event contract version.
pub(crate) use self::token_2022::SPL_TOKEN_2022_EVENT_VERSION;
/// Exact top-level instruction inventory published by the resolved Token-2022 interface.
pub(crate) use self::token_2022::SPL_TOKEN_2022_INSTRUCTION_ENTRIES;
/// Maximum total account metas consumed by one Token-2022 batch.
pub(crate) use self::token_2022::SPL_TOKEN_2022_MAX_BATCH_ACCOUNTS;
/// Maximum decoded sub-instructions in one Token-2022 batch.
pub(crate) use self::token_2022::SPL_TOKEN_2022_MAX_BATCH_INSTRUCTIONS;
/// Maximum retained Token-2022 instruction payload size.
pub(crate) use self::token_2022::SPL_TOKEN_2022_MAX_INSTRUCTION_BYTES;
/// Maximum retained UTF-8 string size for embedded Token Metadata instructions.
pub(crate) use self::token_2022::SPL_TOKEN_2022_MAX_METADATA_STRING_BYTES;
/// Stable Token-2022 surface code.
pub(crate) use self::token_2022::SPL_TOKEN_2022_SURFACE_CODE;
/// Canonical tracing target for the Token-2022 decoder.
pub(crate) use self::token_2022::SPL_TOKEN_2022_TRACING_TARGET;
/// Decodes one bounded Token-2022 instruction.
pub(crate) use self::token_2022::spl_token_2022_decode;
/// Returns the exact entry matching one Token-2022 tag.
pub(crate) use self::token_2022::spl_token_2022_entry_for_tag;
/// Returns the first byte of one retained Token-2022 payload.
pub(crate) use self::token_2022::spl_token_2022_payload_tag;
/// Exact decoder for the SPL Associated Token Account program.
pub use self::associated_token_account::SplAssociatedTokenAccountDecoder;
/// Exact byte length of one SPL ElGamal registry account.
pub use self::elgamal_registry::ELGAMAL_REGISTRY_ACCOUNT_LEN;
/// Parsed SPL ElGamal public-key registry account.
pub use self::elgamal_registry::ElGamalRegistryState;
/// Exact decoder for the SPL ElGamal registry program.
pub use self::elgamal_registry::SplElgamalRegistryDecoder;
/// Parses one exact SPL ElGamal registry account.
pub use self::elgamal_registry::parse_elgamal_registry_state;
/// Exact decoder for the three registered SPL Memo generations.
pub use self::memo::SplMemoDecoder;
/// Exact decoder for the classic SPL Token program.
pub use self::token::SplTokenDecoder;
/// Exact decoder for the Token-2022 program.
pub use self::token_2022::SplToken2022Decoder;
/// Parsed Token-2022 Mint, Account, or Multisig state.
pub use self::token_2022::Token2022State;
/// Exact Token-2022 base account state kind.
pub use self::token_2022::Token2022StateKind;
/// One exact Token-2022 TLV entry.
pub use self::token_2022::Token2022TlvEntry;
/// Parses one Token-2022 Mint, Account, or Multisig state.
pub use self::token_2022::parse_token_2022_state;

View File

@@ -1,10 +1,35 @@
// file: kb-lib/src/decoder/spl/elgamal_registry.rs
// version: 1
// version: 2
//! Migration boundary for legacy crate `kb_decoder_spl_elgamal_registry`.
//! Exact SPL Token-2022 ElGamal public-key registry decoder component.
/// Legacy crate name retained for migration and compatibility tracking.
pub const LEGACY_CRATE: &str = "kb_decoder_spl_elgamal_registry";
mod constants;
mod decoder;
mod state;
mod wire;
/// Current porting status.
pub const MIGRATION_STATUS: &str = "source-preserved-pending-port";
/// Current stable SPL ElGamal registry event contract version.
pub(crate) use self::constants::SPL_ELGAMAL_REGISTRY_EVENT_VERSION;
/// Maximum retained SPL ElGamal registry instruction payload size.
pub(crate) use self::constants::SPL_ELGAMAL_REGISTRY_MAX_INSTRUCTION_BYTES;
/// Stable SPL ElGamal registry surface code.
pub(crate) use self::constants::SPL_ELGAMAL_REGISTRY_SURFACE_CODE;
/// Canonical tracing target for the SPL ElGamal registry decoder.
pub(crate) use self::constants::SPL_ELGAMAL_REGISTRY_TRACING_TARGET;
/// One parsed SPL ElGamal registry instruction.
pub(crate) use self::wire::ParsedRegistryInstruction;
/// Decodes one bounded SPL ElGamal registry instruction.
pub(crate) use self::wire::spl_elgamal_registry_decode;
/// Decodes one bounded SPL ElGamal registry instruction payload.
pub(crate) use self::wire::spl_elgamal_registry_decode_payload;
/// Parses one exact SPL ElGamal registry instruction.
pub(crate) use self::wire::spl_elgamal_registry_parse;
/// Exact decoder for the SPL ElGamal registry program.
pub use self::decoder::SplElgamalRegistryDecoder;
/// Exact byte length of one SPL ElGamal registry account.
pub use self::state::ELGAMAL_REGISTRY_ACCOUNT_LEN;
/// Parsed SPL ElGamal public-key registry account.
pub use self::state::ElGamalRegistryState;
/// Parses one exact SPL ElGamal registry account.
pub use self::state::parse_elgamal_registry_state;

View File

@@ -0,0 +1,11 @@
// file: kb-lib/src/decoder/spl/elgamal_registry/constants.rs
// version: 1
//! Constants for the SPL ElGamal registry decoder.
pub(crate) const SPL_ELGAMAL_REGISTRY_SURFACE_CODE: &str = "spl_elgamal_registry";
pub(crate) const SPL_ELGAMAL_REGISTRY_EVENT_VERSION: u32 = 1;
pub(crate) const SPL_ELGAMAL_REGISTRY_MAX_INSTRUCTION_BYTES: usize = 16;
/// Canonical tracing target for this crate.
pub(crate) const SPL_ELGAMAL_REGISTRY_TRACING_TARGET: &str = "kb-lib.decoder.spl.elgamal_registry";

View File

@@ -0,0 +1,246 @@
// file: kb-lib/src/decoder/spl/elgamal_registry/decoder.rs
// version: 1
//! Exact dispatch for the SPL ElGamal registry program.
const SURFACES: &[crate::DecoderSurface] = &[crate::DecoderSurface {
program_id: kb_program_ids::SPL_TOKEN_2022_ELGAMAL_REGISTRY_PROGRAM_ID,
surface_code: crate::SPL_ELGAMAL_REGISTRY_SURFACE_CODE,
priority: 100,
}];
const PROGRAM_IDS: &[&str] = &[kb_program_ids::SPL_TOKEN_2022_ELGAMAL_REGISTRY_PROGRAM_ID];
/// Decoder for the dedicated Token-2022 ElGamal public-key registry program.
#[derive(Clone, Debug, Default)]
pub struct SplElgamalRegistryDecoder;
impl crate::ProtocolDecoder for crate::SplElgamalRegistryDecoder {
fn decoder_name(&self) -> &'static str {
return "kb_decoder_spl_elgamal_registry";
}
fn decoder_version(&self) -> &'static str {
return env!("CARGO_PKG_VERSION");
}
fn program_ids(&self) -> &'static [&'static str] {
return PROGRAM_IDS;
}
fn supports_observation(
&self,
observation: &crate::ProgramObservation,
) -> crate::DecoderSupport {
return if crate::ProtocolDecoder::handles_program_id(self, &observation.program_id) {
crate::DecoderSupport::Yes
} else {
crate::DecoderSupport::No
};
}
fn decode_observation(
&self,
_observation: &crate::ProgramObservation,
) -> kb_core::Result<std::vec::Vec<crate::DecodedProtocolEvent>> {
return std::result::Result::Ok(std::vec::Vec::new());
}
}
impl crate::InstructionDecoder for crate::SplElgamalRegistryDecoder {
fn identity(&self) -> crate::DecoderIdentity {
return crate::DecoderIdentity {
name: "spl_elgamal_registry".to_string(),
version: env!("CARGO_PKG_VERSION").to_string(),
};
}
fn surfaces(&self) -> &'static [crate::DecoderSurface] {
return SURFACES;
}
fn coverage(&self) -> std::vec::Vec<crate::DecoderCoverageDeclaration> {
return [(0_u8, "create_registry"), (1_u8, "update_registry")]
.into_iter()
.map(|(tag, code)| {
return crate::DecoderCoverageDeclaration {
program_id: kb_program_ids::SPL_TOKEN_2022_ELGAMAL_REGISTRY_PROGRAM_ID
.to_string(),
surface_code: std::option::Option::Some(
crate::SPL_ELGAMAL_REGISTRY_SURFACE_CODE.to_string(),
),
entry_kind: crate::DecoderCoverageEntryKind::Instruction,
entry_code: code.to_string(),
discriminator_hex: std::option::Option::Some(format!("{tag:02x}")),
historical: false,
};
})
.collect();
}
fn recognize(&self, input: &crate::CoreInstructionReplayInput) -> crate::DecoderRecognition {
if input.program_id != kb_program_ids::SPL_TOKEN_2022_ELGAMAL_REGISTRY_PROGRAM_ID {
return crate::DecoderRecognition::incompatible();
}
let entry = input
.instruction_payload_json
.as_ref()
.and_then(|payload| return payload.get("dataBase64"))
.and_then(serde_json::Value::as_str)
.and_then(|encoded| {
use base64::Engine; // rust-rules: trait-import
return base64::engine::general_purpose::STANDARD.decode(encoded.as_bytes()).ok();
})
.and_then(|bytes| return bytes.first().copied())
.and_then(|tag| {
return match tag {
0 => std::option::Option::Some("create_registry".to_string()),
1 => std::option::Option::Some("update_registry".to_string()),
_ => std::option::Option::None,
};
});
return crate::DecoderRecognition::compatible(
entry.is_some(),
100,
std::option::Option::Some(crate::SPL_ELGAMAL_REGISTRY_SURFACE_CODE.to_string()),
entry,
std::option::Option::None,
);
}
fn decode(&self, input: &crate::CoreInstructionReplayInput) -> crate::DecoderExecutionResult {
if input.program_id != kb_program_ids::SPL_TOKEN_2022_ELGAMAL_REGISTRY_PROGRAM_ID {
return crate::DecoderExecutionResult::unsupported(std::option::Option::None);
}
let result = crate::spl_elgamal_registry_decode(input);
if matches!(
result.status,
crate::DecoderOutcomeStatus::Failed | crate::DecoderOutcomeStatus::Unsupported
) {
tracing::error!(
target: crate::SPL_ELGAMAL_REGISTRY_TRACING_TARGET,
action = "decode_failure",
signature = %input.signature,
slot = input.slot,
instruction_path = %input.instruction_path,
program_id = %input.program_id,
processor_name = "spl_elgamal_registry",
processor_version = env!("CARGO_PKG_VERSION"),
input_key = %input.replay_input_key,
payload_hash = ?input.instruction_payload_hash,
transaction_failed = input.transaction_failed,
result_status = ?result.status,
diagnostics = ?result.diagnostics,
"SPL ElGamal registry instruction was not decoded successfully"
);
}
tracing::debug!(
target: crate::SPL_ELGAMAL_REGISTRY_TRACING_TARGET,
action = "decode",
signature = %input.signature,
instruction_path = %input.instruction_path,
program_id = %input.program_id,
transaction_failed = input.transaction_failed,
result_status = ?result.status,
observation_count = result.observations.len(),
"SPL ElGamal registry instruction decode completed"
);
return result;
}
}
#[cfg(test)]
mod tests {
use base64::Engine; // rust-rules: trait-import
fn input(
program_id: &str,
payload: &[u8],
failed: bool,
path: &str,
) -> crate::CoreInstructionReplayInput {
let result = crate::CoreInstructionReplayInput::new(
format!("signature:{path}"),
"signature",
42,
path,
program_id,
failed,
if failed {
std::option::Option::Some(serde_json::json!({"InstructionError":[0,"Custom"]}))
} else {
std::option::Option::None
},
serde_json::json!([]),
serde_json::json!([]),
std::option::Option::Some(serde_json::json!({
"dataBase64": base64::engine::general_purpose::STANDARD.encode(payload)
})),
std::option::Option::None,
serde_json::json!([]),
serde_json::json!([]),
serde_json::json!([]),
serde_json::json!([]),
);
return match result {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => panic!("registry replay input failed: {error}"),
};
}
#[test]
fn exact_program_boundary_and_interface_id_are_preserved() {
assert_eq!(
spl_elgamal_registry_interface::id().to_string(),
kb_program_ids::SPL_TOKEN_2022_ELGAMAL_REGISTRY_PROGRAM_ID
);
let decoder = crate::SplElgamalRegistryDecoder;
assert_eq!(crate::InstructionDecoder::coverage(&decoder).len(), 2);
let foreign = input(kb_program_ids::SPL_TOKEN_2022_PROGRAM_ID, &[0, 1], false, "0");
assert_eq!(
crate::InstructionDecoder::decode(&decoder, &foreign).status,
crate::DecoderOutcomeStatus::Unsupported
);
}
#[test]
fn create_and_update_decode_exact_offsets_and_commit_state() {
for (tag, code, offset, failed, path) in [
(0_u8, "create_registry", 1_i8, false, "0"),
(1_u8, "update_registry", -1_i8, true, "1/0"),
(1_u8, "update_registry", 0_i8, false, "2"),
] {
let input = input(
kb_program_ids::SPL_TOKEN_2022_ELGAMAL_REGISTRY_PROGRAM_ID,
&[tag, offset as u8],
failed,
path,
);
let result =
crate::InstructionDecoder::decode(&crate::SplElgamalRegistryDecoder, &input);
assert_eq!(result.status, crate::DecoderOutcomeStatus::Decoded);
assert_eq!(result.recognized_entry_code.as_deref(), std::option::Option::Some(code));
assert_eq!(
result.observations[0].payload_json["proofInstructionOffset"],
serde_json::json!(offset)
);
assert_eq!(result.observations[0].observation_committed, !failed);
}
}
#[test]
fn malformed_unknown_and_suffixed_wire_fail_closed() {
for payload in [std::vec::Vec::new(), vec![0], vec![2, 0], vec![0, 1, 2]] {
let input = input(
kb_program_ids::SPL_TOKEN_2022_ELGAMAL_REGISTRY_PROGRAM_ID,
payload.as_slice(),
false,
"0",
);
let result =
crate::InstructionDecoder::decode(&crate::SplElgamalRegistryDecoder, &input);
assert_eq!(result.status, crate::DecoderOutcomeStatus::Failed);
assert!(result.observations.is_empty());
}
}
}

View File

@@ -0,0 +1,76 @@
// file: kb-lib/src/decoder/spl/elgamal_registry/state.rs
// version: 1
//! Strict SPL ElGamal registry account-state parsing.
use base64::Engine; // rust-rules: trait-import
/// Exact byte length of one SPL ElGamal registry account.
pub const ELGAMAL_REGISTRY_ACCOUNT_LEN: usize = 64;
/// Public state retained by one SPL ElGamal registry account.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ElGamalRegistryState {
/// Wallet address associated with this registry.
pub owner: String,
/// Exact 32-byte ElGamal public key encoded as standard base64.
pub elgamal_pubkey_base64: String,
/// Exact account bytes encoded as lowercase hexadecimal.
pub wire_hex: String,
}
/// Parse one exact SPL ElGamal registry account.
pub fn parse_elgamal_registry_state(
data: &[u8],
) -> std::result::Result<ElGamalRegistryState, std::string::String> {
if data.len() != ELGAMAL_REGISTRY_ACCOUNT_LEN {
return std::result::Result::Err(format!(
"SPL ElGamal registry account requires exactly {ELGAMAL_REGISTRY_ACCOUNT_LEN} bytes; received {}",
data.len()
));
}
return std::result::Result::Ok(ElGamalRegistryState {
owner: bs58::encode(&data[..32]).into_string(),
elgamal_pubkey_base64: base64::engine::general_purpose::STANDARD.encode(&data[32..64]),
wire_hex: lower_hex(data),
});
}
fn lower_hex(bytes: &[u8]) -> String {
let mut output = String::with_capacity(bytes.len() * 2);
for byte in bytes {
output.push_str(&format!("{byte:02x}"));
}
return output;
}
#[cfg(test)]
mod tests {
use base64::Engine; // rust-rules: trait-import
#[test]
fn exact_registry_state_preserves_owner_key_and_wire() {
let mut data = [0u8; crate::ELGAMAL_REGISTRY_ACCOUNT_LEN];
data[..32].fill(7);
data[32..].fill(9);
let parsed = crate::parse_elgamal_registry_state(&data);
assert_eq!(
parsed.as_ref().map(|state| return state.owner.clone()),
std::result::Result::Ok(bs58::encode([7u8; 32]).into_string())
);
assert_eq!(
parsed.as_ref().map(|state| return state.elgamal_pubkey_base64.clone()),
std::result::Result::Ok(base64::engine::general_purpose::STANDARD.encode([9u8; 32]))
);
assert_eq!(
parsed.as_ref().map(|state| return state.wire_hex.len()),
std::result::Result::Ok(128)
);
}
#[test]
fn registry_state_rejects_every_non_exact_length() {
assert!(crate::parse_elgamal_registry_state(&[0; 63]).is_err());
assert!(crate::parse_elgamal_registry_state(&[0; 65]).is_err());
}
}

View File

@@ -0,0 +1,195 @@
// file: kb-lib/src/decoder/spl/elgamal_registry/wire.rs
// version: 1
//! Exact two-byte SPL ElGamal registry instruction decoding.
use base64::Engine; // rust-rules: trait-import
use sha2::Digest; // rust-rules: trait-import
#[derive(Clone, Debug)]
pub(crate) struct ParsedRegistryInstruction {
pub(crate) code: &'static str,
pub(crate) tag: u8,
pub(crate) proof_instruction_offset: i8,
}
pub(crate) fn spl_elgamal_registry_decode_payload(
input: &crate::CoreInstructionReplayInput,
) -> std::result::Result<std::vec::Vec<u8>, std::string::String> {
let payload = match input.instruction_payload_json.as_ref() {
std::option::Option::Some(value) => value,
std::option::Option::None => {
return std::result::Result::Err(
"ElGamal registry instruction payload is not retained".to_string(),
);
},
};
let encoded = match payload.get("dataBase64").and_then(serde_json::Value::as_str) {
std::option::Option::Some(value) => value,
std::option::Option::None => {
return std::result::Result::Err(
"ElGamal registry payload does not contain dataBase64".to_string(),
);
},
};
if encoded.len() > 32 {
return std::result::Result::Err(
"ElGamal registry base64 payload is too large".to_string(),
);
}
let bytes = match base64::engine::general_purpose::STANDARD.decode(encoded.as_bytes()) {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => {
return std::result::Result::Err(format!(
"ElGamal registry payload is not valid base64: {error}"
));
},
};
if bytes.len() > crate::SPL_ELGAMAL_REGISTRY_MAX_INSTRUCTION_BYTES {
return std::result::Result::Err(format!(
"ElGamal registry payload exceeds {} bytes",
crate::SPL_ELGAMAL_REGISTRY_MAX_INSTRUCTION_BYTES
));
}
return std::result::Result::Ok(bytes);
}
pub(crate) fn spl_elgamal_registry_parse(
bytes: &[u8],
) -> std::result::Result<crate::ParsedRegistryInstruction, std::string::String> {
if bytes.len() != 2 {
return std::result::Result::Err(format!(
"ElGamal registry instruction requires exactly 2 bytes; received {}",
bytes.len()
));
}
let code = match bytes[0] {
0 => "create_registry",
1 => "update_registry",
tag => return std::result::Result::Err(format!("unknown ElGamal registry tag {tag}")),
};
return std::result::Result::Ok(crate::ParsedRegistryInstruction {
code,
tag: bytes[0],
proof_instruction_offset: bytes[1] as i8,
});
}
pub(crate) fn spl_elgamal_registry_decode(
input: &crate::CoreInstructionReplayInput,
) -> crate::DecoderExecutionResult {
let bytes = match crate::spl_elgamal_registry_decode_payload(input) {
std::result::Result::Ok(value) => value,
std::result::Result::Err(message) => {
return crate::DecoderExecutionResult {
status: crate::DecoderOutcomeStatus::Failed,
recognized_entry_code: std::option::Option::None,
observations: std::vec::Vec::new(),
diagnostics: std::vec![crate::DecoderDiagnostic {
code: "elgamal_registry_payload_invalid".to_string(),
message,
retriable: false,
}],
};
},
};
let parsed = match crate::spl_elgamal_registry_parse(bytes.as_slice()) {
std::result::Result::Ok(value) => value,
std::result::Result::Err(message) => {
return crate::DecoderExecutionResult {
status: crate::DecoderOutcomeStatus::Failed,
recognized_entry_code: bytes.first().and_then(|tag| {
return match tag {
0 => std::option::Option::Some("create_registry".to_string()),
1 => std::option::Option::Some("update_registry".to_string()),
_ => std::option::Option::None,
};
}),
observations: std::vec::Vec::new(),
diagnostics: std::vec![crate::DecoderDiagnostic {
code: "elgamal_registry_wire_invalid".to_string(),
message,
retriable: false,
}],
};
},
};
let committed = !input.transaction_failed;
let wire_hash = hash(bytes.as_slice());
let event = crate::DecodedProtocolEvent {
signature: crate::Signature(input.signature.clone()),
slot: crate::Slot(input.slot),
instruction_path: crate::InstructionPath(input.instruction_path.clone()),
program_id: crate::ProgramId(input.program_id.clone()),
protocol_code: crate::ProtocolCode(crate::SPL_ELGAMAL_REGISTRY_SURFACE_CODE.to_string()),
surface_code: crate::SurfaceCode(crate::SPL_ELGAMAL_REGISTRY_SURFACE_CODE.to_string()),
event_code: crate::EventCode(format!(
"{}.{}",
crate::SPL_ELGAMAL_REGISTRY_SURFACE_CODE,
parsed.code
)),
event_name: crate::EventName(parsed.code.to_string()),
event_family: crate::EventFamily::Admin,
source_kind: if input.instruction_path.contains('/') {
crate::EventSourceKind::InnerInstruction
} else {
crate::EventSourceKind::Instruction
},
confidence: crate::DecoderConfidence::ManualExact,
};
let observation = crate::DecodedObservation {
event_key: format!("elgamal_registry:{}:0", parsed.code),
event,
payload_json: serde_json::json!({
"eventVersion": crate::SPL_ELGAMAL_REGISTRY_EVENT_VERSION,
"instruction": parsed.code,
"wireTag": parsed.tag,
"proofInstructionOffset": parsed.proof_instruction_offset,
"proofLocationKind": if parsed.proof_instruction_offset == 0 { "context_state_account" } else { "relative_instruction_offset" },
"instructionPath": input.instruction_path,
"instructionLocation": if input.instruction_path.contains('/') { "inner" } else { "outer" },
"transactionSucceeded": !input.transaction_failed,
"committed": committed,
"accounts": input.instruction_accounts_json,
"wire": {
"lengthBytes": bytes.len(),
"sha256": wire_hash,
"prefixHex": hex(bytes.as_slice()),
"complete": true,
},
"programBoundary": {
"registryProgramId": kb_program_ids::SPL_TOKEN_2022_ELGAMAL_REGISTRY_PROGRAM_ID,
"token2022ProgramId": kb_program_ids::SPL_TOKEN_2022_PROGRAM_ID,
"zkProofProgramId": kb_program_ids::ZK_ELGAMAL_PROOF_PROGRAM_ID,
"proofDecodedHere": false,
}
}),
transaction_failed: input.transaction_failed,
transaction_error: input.transaction_err_json.clone(),
observation_committed: committed,
proof: crate::DecoderProof {
kind: crate::DecoderProofKind::Manual,
confidence: crate::DecoderConfidence::ManualExact,
evidence: std::vec![
"spl_elgamal_registry_interface_0_2_1_registry_instruction_unpack".to_string(),
format!("wire_tag:{}", parsed.tag),
format!("wire_sha256:{wire_hash}"),
],
},
};
return crate::DecoderExecutionResult {
status: crate::DecoderOutcomeStatus::Decoded,
recognized_entry_code: std::option::Option::Some(parsed.code.to_string()),
observations: std::vec![observation],
diagnostics: std::vec::Vec::new(),
};
}
fn hash(bytes: &[u8]) -> std::string::String {
let digest = sha2::Sha256::digest(bytes);
return digest.iter().map(|byte| return format!("{byte:02x}")).collect();
}
fn hex(bytes: &[u8]) -> std::string::String {
return bytes.iter().map(|byte| return format!("{byte:02x}")).collect();
}

View File

@@ -1,10 +1,45 @@
// file: kb-lib/src/decoder/spl/token_2022.rs
// version: 1
// version: 2
//! Migration boundary for legacy crate `kb_decoder_spl_token_2022`.
//! Exact Token-2022 instruction and state decoder component.
/// Legacy crate name retained for migration and compatibility tracking.
pub const LEGACY_CRATE: &str = "kb_decoder_spl_token_2022";
mod constants;
mod decoder;
mod state;
mod wire;
/// Current porting status.
pub const MIGRATION_STATUS: &str = "source-preserved-pending-port";
/// Maximum prefix retained in bounded Token-2022 diagnostics.
pub(crate) use self::constants::SPL_TOKEN_2022_DIAGNOSTIC_PREFIX_BYTES;
/// Current stable Token-2022 decoded event contract version.
pub(crate) use self::constants::SPL_TOKEN_2022_EVENT_VERSION;
/// Exact top-level instruction inventory published by the resolved Token-2022 interface.
pub(crate) use self::constants::SPL_TOKEN_2022_INSTRUCTION_ENTRIES;
/// Maximum total account metas consumed by one Token-2022 batch.
pub(crate) use self::constants::SPL_TOKEN_2022_MAX_BATCH_ACCOUNTS;
/// Maximum decoded sub-instructions in one Token-2022 batch.
pub(crate) use self::constants::SPL_TOKEN_2022_MAX_BATCH_INSTRUCTIONS;
/// Maximum retained Token-2022 instruction payload size.
pub(crate) use self::constants::SPL_TOKEN_2022_MAX_INSTRUCTION_BYTES;
/// Maximum retained UTF-8 string size for embedded Token Metadata instructions.
pub(crate) use self::constants::SPL_TOKEN_2022_MAX_METADATA_STRING_BYTES;
/// Stable Token-2022 surface code.
pub(crate) use self::constants::SPL_TOKEN_2022_SURFACE_CODE;
/// Canonical tracing target for the Token-2022 decoder.
pub(crate) use self::constants::SPL_TOKEN_2022_TRACING_TARGET;
/// Decodes one bounded Token-2022 instruction.
pub(crate) use self::wire::spl_token_2022_decode;
/// Returns the exact entry matching one Token-2022 tag.
pub(crate) use self::wire::spl_token_2022_entry_for_tag;
/// Returns the first byte of one retained Token-2022 payload.
pub(crate) use self::wire::spl_token_2022_payload_tag;
/// Exact decoder for the Token-2022 program.
pub use self::decoder::SplToken2022Decoder;
/// Parsed Token-2022 Mint, Account, or Multisig state.
pub use self::state::Token2022State;
/// Exact Token-2022 base account state kind.
pub use self::state::Token2022StateKind;
/// One exact Token-2022 TLV entry.
pub use self::state::Token2022TlvEntry;
/// Parses one Token-2022 Mint, Account, or Multisig state.
pub use self::state::parse_token_2022_state;

View File

@@ -0,0 +1,72 @@
// file: kb-lib/src/decoder/spl/token_2022/constants.rs
// version: 1
//! Local constants for the exact Token-2022 decoder. Program identifiers live in `kb_program_ids`.
/// Stable Token-2022 surface code.
pub(crate) const SPL_TOKEN_2022_SURFACE_CODE: &str = "spl_token_2022";
/// Current decoded event contract version.
pub(crate) const SPL_TOKEN_2022_EVENT_VERSION: u32 = 1;
/// Maximum retained instruction payload size.
pub(crate) const SPL_TOKEN_2022_MAX_INSTRUCTION_BYTES: usize = 16_384;
/// Maximum retained UTF-8 string size for embedded Token Metadata instructions.
pub(crate) const SPL_TOKEN_2022_MAX_METADATA_STRING_BYTES: usize = 4_096;
/// Maximum prefix retained in diagnostics.
pub(crate) const SPL_TOKEN_2022_DIAGNOSTIC_PREFIX_BYTES: usize = 32;
/// Maximum decoded sub-instructions in one batch.
pub(crate) const SPL_TOKEN_2022_MAX_BATCH_INSTRUCTIONS: usize = 64;
/// Maximum total account metas consumed by one batch.
pub(crate) const SPL_TOKEN_2022_MAX_BATCH_ACCOUNTS: usize = 512;
/// Exact top-level instruction inventory published by the resolved Token-2022 interface.
pub(crate) const SPL_TOKEN_2022_INSTRUCTION_ENTRIES: &[(u8, &str, bool)] = &[
(0, "initialize_mint", false),
(1, "initialize_account", false),
(2, "initialize_multisig", false),
(3, "transfer", false),
(4, "approve", false),
(5, "revoke", false),
(6, "set_authority", false),
(7, "mint_to", false),
(8, "burn", false),
(9, "close_account", false),
(10, "freeze_account", false),
(11, "thaw_account", false),
(12, "transfer_checked", false),
(13, "approve_checked", false),
(14, "mint_to_checked", false),
(15, "burn_checked", false),
(16, "initialize_account2", false),
(17, "sync_native", false),
(18, "initialize_account3", false),
(19, "initialize_multisig2", false),
(20, "initialize_mint2", false),
(21, "get_account_data_size", false),
(22, "initialize_immutable_owner", false),
(23, "amount_to_ui_amount", false),
(24, "ui_amount_to_amount", false),
(25, "initialize_mint_close_authority", false),
(26, "transfer_fee_extension", false),
(27, "confidential_transfer_extension", false),
(28, "default_account_state_extension", false),
(29, "reallocate", false),
(30, "memo_transfer_extension", false),
(31, "create_native_mint", false),
(32, "initialize_non_transferable_mint", false),
(33, "interest_bearing_mint_extension", false),
(34, "cpi_guard_extension", false),
(35, "initialize_permanent_delegate", false),
(36, "transfer_hook_extension", false),
(37, "confidential_transfer_fee_extension", false),
(38, "withdraw_excess_lamports", false),
(39, "metadata_pointer_extension", false),
(40, "group_pointer_extension", false),
(41, "group_member_pointer_extension", false),
(42, "confidential_mint_burn_extension", false),
(43, "scaled_ui_amount_extension", false),
(44, "pausable_extension", false),
(45, "unwrap_lamports", false),
(46, "permissioned_burn_extension", false),
(255, "batch", false),
];
/// Canonical tracing target for this crate.
pub(crate) const SPL_TOKEN_2022_TRACING_TARGET: &str = "kb-lib.decoder.spl.token_2022";

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
// file: kb-lib/src/lib.rs
// version: 9
// version: 10
//! Consolidated decoder, executor, materializer and shared model library.
#![warn(missing_docs)]
@@ -11,6 +11,8 @@ pub mod executor;
pub mod materializer;
pub mod model;
/// One parsed SPL ElGamal registry instruction.
pub(crate) use crate::decoder::ParsedRegistryInstruction;
/// Current stable Associated Token Account decoded event contract version.
pub(crate) use crate::decoder::SPL_ASSOCIATED_TOKEN_ACCOUNT_EVENT_VERSION;
/// Exact Associated Token Account instructions published by the official interface.
@@ -29,6 +31,14 @@ pub(crate) use crate::decoder::SPL_ASSOCIATED_TOKEN_ACCOUNT_MAX_TRANSACTION_KEYS
pub(crate) use crate::decoder::SPL_ASSOCIATED_TOKEN_ACCOUNT_SURFACE_CODE;
/// Canonical tracing target for the Associated Token Account decoder.
pub(crate) use crate::decoder::SPL_ASSOCIATED_TOKEN_ACCOUNT_TRACING_TARGET;
/// Current stable SPL ElGamal registry event contract version.
pub(crate) use crate::decoder::SPL_ELGAMAL_REGISTRY_EVENT_VERSION;
/// Maximum retained SPL ElGamal registry instruction payload size.
pub(crate) use crate::decoder::SPL_ELGAMAL_REGISTRY_MAX_INSTRUCTION_BYTES;
/// Stable SPL ElGamal registry surface code.
pub(crate) use crate::decoder::SPL_ELGAMAL_REGISTRY_SURFACE_CODE;
/// Canonical tracing target for the SPL ElGamal registry decoder.
pub(crate) use crate::decoder::SPL_ELGAMAL_REGISTRY_TRACING_TARGET;
/// Maximum payload prefix retained for bounded Memo diagnostics.
pub(crate) use crate::decoder::SPL_MEMO_DIAGNOSTIC_PREFIX_BYTES;
/// Current stable Memo decoded event contract version.
@@ -45,6 +55,24 @@ pub(crate) use crate::decoder::SPL_MEMO_V1_SURFACE_CODE;
pub(crate) use crate::decoder::SPL_MEMO_V3_SURFACE_CODE;
/// Stable Memo v4 surface code.
pub(crate) use crate::decoder::SPL_MEMO_V4_SURFACE_CODE;
/// Maximum prefix retained in bounded Token-2022 diagnostics.
pub(crate) use crate::decoder::SPL_TOKEN_2022_DIAGNOSTIC_PREFIX_BYTES;
/// Current stable Token-2022 decoded event contract version.
pub(crate) use crate::decoder::SPL_TOKEN_2022_EVENT_VERSION;
/// Exact top-level instruction inventory published by the resolved Token-2022 interface.
pub(crate) use crate::decoder::SPL_TOKEN_2022_INSTRUCTION_ENTRIES;
/// Maximum total account metas consumed by one Token-2022 batch.
pub(crate) use crate::decoder::SPL_TOKEN_2022_MAX_BATCH_ACCOUNTS;
/// Maximum decoded sub-instructions in one Token-2022 batch.
pub(crate) use crate::decoder::SPL_TOKEN_2022_MAX_BATCH_INSTRUCTIONS;
/// Maximum retained Token-2022 instruction payload size.
pub(crate) use crate::decoder::SPL_TOKEN_2022_MAX_INSTRUCTION_BYTES;
/// Maximum retained UTF-8 string size for embedded Token Metadata instructions.
pub(crate) use crate::decoder::SPL_TOKEN_2022_MAX_METADATA_STRING_BYTES;
/// Stable Token-2022 surface code.
pub(crate) use crate::decoder::SPL_TOKEN_2022_SURFACE_CODE;
/// Canonical tracing target for the Token-2022 decoder.
pub(crate) use crate::decoder::SPL_TOKEN_2022_TRACING_TARGET;
/// Maximum prefix retained in bounded classic SPL Token diagnostics.
pub(crate) use crate::decoder::SPL_TOKEN_DIAGNOSTIC_PREFIX_BYTES;
/// Current stable classic SPL Token decoded event contract version.
@@ -89,43 +117,6 @@ pub(crate) use crate::decoder::solana::SOLANA_CORE_NATIVE_EVENT_VERSION;
pub(crate) use crate::decoder::solana::SOLANA_CORE_NATIVE_LOADER_SURFACE_CODE;
/// Maximum number of component bytes retained as a hexadecimal event prefix.
pub(crate) use crate::decoder::solana::SOLANA_CORE_PRECOMPILE_COMPONENT_PREFIX_BYTES;
/// Expected role and privileges for one positional instruction account.
pub(crate) use crate::decoder::solana::SolanaCoreAccountRole;
/// Returns declared Address Lookup Table instruction coverage.
pub(crate) use crate::decoder::solana::solana_core_address_lookup_table_coverage;
/// Decodes one Address Lookup Table instruction.
pub(crate) use crate::decoder::solana::solana_core_address_lookup_table_decode;
/// Recognizes one Address Lookup Table instruction without producing an event.
pub(crate) use crate::decoder::solana::solana_core_address_lookup_table_recognize;
/// Returns declared Compute Budget instruction coverage.
pub(crate) use crate::decoder::solana::solana_core_compute_budget_coverage;
/// Decodes one Compute Budget instruction.
pub(crate) use crate::decoder::solana::solana_core_compute_budget_decode;
/// Recognizes one Compute Budget instruction without producing an event.
pub(crate) use crate::decoder::solana::solana_core_compute_budget_recognize;
/// Returns declared Config Program instruction coverage.
pub(crate) use crate::decoder::solana::solana_core_config_coverage;
/// Decodes one generic Config Program store instruction.
pub(crate) use crate::decoder::solana::solana_core_config_decode;
/// Recognizes one generic Config Program store instruction.
pub(crate) use crate::decoder::solana::solana_core_config_recognize;
/// Resolves positional instruction accounts and validates their core indexes.
pub(crate) use crate::decoder::solana::solana_core_resolve_accounts;
/// Decodes one bounded Associated Token Account instruction.
pub(crate) use crate::decoder::spl_associated_token_account_decode;
/// Returns the exact entry matching an Associated Token Account wire.
pub(crate) use crate::decoder::spl_associated_token_account_entry;
/// Reads one bounded Associated Token Account payload.
pub(crate) use crate::decoder::spl_associated_token_account_payload;
/// Decodes one bounded SPL Memo instruction.
pub(crate) use crate::decoder::spl_memo_decode;
/// Decodes one bounded classic SPL Token instruction.
pub(crate) use crate::decoder::spl_token_decode;
/// Returns the published entry matching one classic SPL Token tag.
pub(crate) use crate::decoder::spl_token_entry_for_tag;
/// Returns the first byte of one retained classic SPL Token payload.
pub(crate) use crate::decoder::spl_token_payload_tag;
/// Stable protocol code shared by native Solana events.
pub(crate) use crate::decoder::solana::SOLANA_CORE_PROTOCOL_CODE;
/// Byte length of a secp256k1 Ethereum address.
@@ -158,12 +149,32 @@ pub(crate) use crate::decoder::solana::SOLANA_CORE_VOTE_SURFACE_CODE;
pub(crate) use crate::decoder::solana::SOLANA_CORE_ZK_ELGAMAL_PROOF_SURFACE_CODE;
/// Stable historical ZK Token Proof surface code.
pub(crate) use crate::decoder::solana::SOLANA_CORE_ZK_TOKEN_PROOF_SURFACE_CODE;
/// Expected role and privileges for one positional instruction account.
pub(crate) use crate::decoder::solana::SolanaCoreAccountRole;
/// One resolved outer instruction payload and its provenance relative to the target instruction.
pub(crate) use crate::decoder::solana::SolanaCoreResolvedInstructionPayload;
/// Returns declared Address Lookup Table instruction coverage.
pub(crate) use crate::decoder::solana::solana_core_address_lookup_table_coverage;
/// Decodes one Address Lookup Table instruction.
pub(crate) use crate::decoder::solana::solana_core_address_lookup_table_decode;
/// Recognizes one Address Lookup Table instruction without producing an event.
pub(crate) use crate::decoder::solana::solana_core_address_lookup_table_recognize;
/// Returns a hexadecimal prefix no longer than the available byte slice.
pub(crate) use crate::decoder::solana::solana_core_bounded_hexadecimal_prefix;
/// Extracts one exact bounded byte slice with checked arithmetic.
pub(crate) use crate::decoder::solana::solana_core_bounded_slice;
/// Returns declared Compute Budget instruction coverage.
pub(crate) use crate::decoder::solana::solana_core_compute_budget_coverage;
/// Decodes one Compute Budget instruction.
pub(crate) use crate::decoder::solana::solana_core_compute_budget_decode;
/// Recognizes one Compute Budget instruction without producing an event.
pub(crate) use crate::decoder::solana::solana_core_compute_budget_recognize;
/// Returns declared Config Program instruction coverage.
pub(crate) use crate::decoder::solana::solana_core_config_coverage;
/// Decodes one generic Config Program store instruction.
pub(crate) use crate::decoder::solana::solana_core_config_decode;
/// Recognizes one generic Config Program store instruction.
pub(crate) use crate::decoder::solana::solana_core_config_recognize;
/// Decodes one retained base64 instruction payload with an explicit byte limit.
pub(crate) use crate::decoder::solana::solana_core_decode_instruction_data;
/// Returns the decoded target payload length when retained and valid.
@@ -202,6 +213,8 @@ pub(crate) use crate::decoder::solana::solana_core_precompiles_recognize;
pub(crate) use crate::decoder::solana::solana_core_read_u32_le;
/// Reads one little-endian `u64` from an exact byte range.
pub(crate) use crate::decoder::solana::solana_core_read_u64_le;
/// Resolves positional instruction accounts and validates their core indexes.
pub(crate) use crate::decoder::solana::solana_core_resolve_accounts;
/// Resolves a secp256k1 instruction reference. The runtime format has no current-instruction
/// sentinel: every `u8` value is an explicit outer instruction index.
pub(crate) use crate::decoder::solana::solana_core_resolve_u8_instruction_payload;
@@ -247,13 +260,53 @@ pub(crate) use crate::decoder::solana::solana_core_zk_token_proof_coverage;
pub(crate) use crate::decoder::solana::solana_core_zk_token_proof_decode;
/// Recognizes one historical ZK Token Proof layout or the current no-op runtime fallback.
pub(crate) use crate::decoder::solana::solana_core_zk_token_proof_recognize;
/// Decodes one bounded Associated Token Account instruction.
pub(crate) use crate::decoder::spl_associated_token_account_decode;
/// Returns the exact entry matching an Associated Token Account wire.
pub(crate) use crate::decoder::spl_associated_token_account_entry;
/// Reads one bounded Associated Token Account payload.
pub(crate) use crate::decoder::spl_associated_token_account_payload;
/// Decodes one bounded SPL ElGamal registry instruction.
pub(crate) use crate::decoder::spl_elgamal_registry_decode;
/// Decodes one bounded SPL ElGamal registry instruction payload.
pub(crate) use crate::decoder::spl_elgamal_registry_decode_payload;
/// Parses one exact SPL ElGamal registry instruction.
pub(crate) use crate::decoder::spl_elgamal_registry_parse;
/// Decodes one bounded SPL Memo instruction.
pub(crate) use crate::decoder::spl_memo_decode;
/// Decodes one bounded Token-2022 instruction.
pub(crate) use crate::decoder::spl_token_2022_decode;
/// Returns the exact entry matching one Token-2022 tag.
pub(crate) use crate::decoder::spl_token_2022_entry_for_tag;
/// Returns the first byte of one retained Token-2022 payload.
pub(crate) use crate::decoder::spl_token_2022_payload_tag;
/// Decodes one bounded classic SPL Token instruction.
pub(crate) use crate::decoder::spl_token_decode;
/// Returns the published entry matching one classic SPL Token tag.
pub(crate) use crate::decoder::spl_token_entry_for_tag;
/// Returns the first byte of one retained classic SPL Token payload.
pub(crate) use crate::decoder::spl_token_payload_tag;
/// Exact byte length of one SPL ElGamal registry account.
pub use crate::decoder::ELGAMAL_REGISTRY_ACCOUNT_LEN;
/// Parsed SPL ElGamal public-key registry account.
pub use crate::decoder::ElGamalRegistryState;
/// Exact decoder for the SPL Associated Token Account program.
pub use crate::decoder::SplAssociatedTokenAccountDecoder;
/// Exact decoder for the SPL ElGamal registry program.
pub use crate::decoder::SplElgamalRegistryDecoder;
/// Exact decoder for the three registered SPL Memo generations.
pub use crate::decoder::SplMemoDecoder;
/// Exact decoder for the Token-2022 program.
pub use crate::decoder::SplToken2022Decoder;
/// Exact decoder for the classic SPL Token program.
pub use crate::decoder::SplTokenDecoder;
/// Parsed Token-2022 Mint, Account, or Multisig state.
pub use crate::decoder::Token2022State;
/// Exact Token-2022 base account state kind.
pub use crate::decoder::Token2022StateKind;
/// One exact Token-2022 TLV entry.
pub use crate::decoder::Token2022TlvEntry;
/// Current contextual core instruction input contract version.
pub use crate::decoder::api::contracts::CORE_INSTRUCTION_INPUT_CONTRACT_VERSION;
/// Stable contextual decoded observation.
@@ -294,6 +347,10 @@ pub use crate::decoder::api::decoder::DecoderSupport;
pub use crate::decoder::api::decoder::InitialDecoder;
/// Exposes the common protocol decoder trait.
pub use crate::decoder::api::decoder::ProtocolDecoder;
/// Parses one exact SPL ElGamal registry account.
pub use crate::decoder::parse_elgamal_registry_state;
/// Parses one Token-2022 Mint, Account, or Multisig state.
pub use crate::decoder::parse_token_2022_state;
/// Runtime-native Solana decoder with maximal native instruction coverage.
pub use crate::decoder::solana::SolanaCoreDecoder;
/// Exposes the blockhash policy kind.

View File

@@ -1,11 +1,15 @@
<!-- file: kb-program-ids/README.md -->
<!-- version: 4 -->
<!-- version: 5 -->
# kb-program-ids
`kb-program-ids` est la source unique des identifiants de programmes Solana et des comptes natifs connus utilisés par le workspace.
La tranche `0.1.0-pre.004` expose les 18 surfaces exécutables nécessaires au décodeur Solana Core, les comptes natifs associés utilisés par leurs contrats et lidentifiant SPL Token classique employé par les tests de frontière. La tranche `0.1.0-pre.005` ajoute les trois identifiants SPL Memo v1, v3 et v4 sans les classer parmi les surfaces natives. `0.1.0-pre.006` active lidentifiant SPL Token classique dans un décodeur concret tout en le maintenant hors des surfaces natives. `0.1.0-pre.007` ajoute les identifiants SPL Associated Token Account et Token2022 nécessaires à la frontière ATA, toujours sans les classer parmi les surfaces natives.
La tranche `0.1.0-pre.004` expose les 18 surfaces exécutables nécessaires au décodeur Solana Core, les comptes natifs associés utilisés par leurs contrats et lidentifiant SPL Token classique employé par les tests de frontière. La tranche `0.1.0-pre.005` ajoute les trois identifiants SPL Memo v1, v3 et v4 sans les classer parmi les surfaces natives. `0.1.0-pre.006` active lidentifiant SPL Token classique dans un décodeur concret tout en le maintenant hors des surfaces natives. `0.1.0-pre.007` ajoute les identifiants SPL Associated Token Account et Token2022 nécessaires à la frontière ATA. `0.1.0-pre.008` ajoute le Program ID indépendant du registre ElGamal de Token2022, toujours hors des surfaces natives.
`constants.rs` reste lunique source des adresses et des tableaux statiques. `programs.rs` porte
`ProgramIdEntry`, ses méthodes et toutes les fonctions de consultation. `lib.rs` se limite aux
déclarations de modules et aux réexports documentés de la façade.
## API publique

View File

@@ -1,5 +1,5 @@
// file: kb-program-ids/src/constants.rs
// version: 3
// version: 4
//! Canonical Solana program and well-known account identifiers.
@@ -43,6 +43,9 @@ pub const SPL_MEMO_V4_PROGRAM_ID: &str = "Memo4c2pN8afCj432Lb7RMVKi9PbQnnW7ewFFa
pub const SPL_TOKEN_PROGRAM_ID: &str = "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA";
/// SPL Token-2022 program identifier.
pub const SPL_TOKEN_2022_PROGRAM_ID: &str = "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb";
/// SPL Token-2022 ElGamal public-key registry program identifier.
pub const SPL_TOKEN_2022_ELGAMAL_REGISTRY_PROGRAM_ID: &str =
"regVYJW7tcT8zipN5YiBvHsvR5jXW1uLFxaHSbugABg";
/// Historical Stake configuration account identifier.
pub const STAKE_CONFIG_ACCOUNT_ID: &str = "StakeConfig11111111111111111111111111111111";
/// Compatibility alias for the historical Stake configuration account identifier.
@@ -235,6 +238,10 @@ pub(crate) const PROGRAM_ID_ENTRIES: &[crate::ProgramIdEntry] = &[
name: "spl_token_2022",
address: crate::SPL_TOKEN_2022_PROGRAM_ID,
},
crate::ProgramIdEntry {
name: "spl_token_2022_elgamal_registry",
address: crate::SPL_TOKEN_2022_ELGAMAL_REGISTRY_PROGRAM_ID,
},
crate::ProgramIdEntry {
name: "stake_config",
address: crate::STAKE_CONFIG_ACCOUNT_ID,

View File

@@ -1,5 +1,5 @@
// file: kb-program-ids/src/lib.rs
// version: 5
// version: 7
#![forbid(unsafe_code)]
#![deny(unreachable_pub)]
@@ -8,6 +8,14 @@
//! Shared canonical Solana program identifiers.
mod constants;
mod programs;
/// Internal list of executable native programs.
pub(crate) use constants::NATIVE_PROGRAM_ID_ENTRIES;
/// Internal list of native well-known accounts.
pub(crate) use constants::NATIVE_WELL_KNOWN_ACCOUNT_ID_ENTRIES;
/// Internal list of currently registered identifiers.
pub(crate) use constants::PROGRAM_ID_ENTRIES;
/// Address Lookup Table program identifier.
pub use constants::ADDRESS_LOOKUP_TABLE_PROGRAM_ID;
@@ -33,12 +41,6 @@ pub use constants::INCINERATOR_PROGRAM_ID;
pub use constants::LOADER_V4_PROGRAM_ID;
/// Native Loader program identifier.
pub use constants::NATIVE_LOADER_PROGRAM_ID;
/// Internal list of executable native programs.
pub(crate) use constants::NATIVE_PROGRAM_ID_ENTRIES;
/// Internal list of native well-known accounts.
pub(crate) use constants::NATIVE_WELL_KNOWN_ACCOUNT_ID_ENTRIES;
/// Internal list of currently registered identifiers.
pub(crate) use constants::PROGRAM_ID_ENTRIES;
/// Secp256k1 precompile program identifier.
pub use constants::SECP256K1_PROGRAM_ID;
/// Secp256r1 precompile program identifier.
@@ -51,6 +53,8 @@ pub use constants::SPL_MEMO_V1_PROGRAM_ID;
pub use constants::SPL_MEMO_V3_PROGRAM_ID;
/// Current SPL Memo v4 program identifier.
pub use constants::SPL_MEMO_V4_PROGRAM_ID;
/// SPL Token-2022 ElGamal public-key registry program identifier.
pub use constants::SPL_TOKEN_2022_ELGAMAL_REGISTRY_PROGRAM_ID;
/// SPL Token-2022 program identifier.
pub use constants::SPL_TOKEN_2022_PROGRAM_ID;
/// Classic SPL Token program identifier.
@@ -79,142 +83,15 @@ pub use constants::VOTE_PROGRAM_ID;
pub use constants::ZK_ELGAMAL_PROOF_PROGRAM_ID;
/// ZK Token Proof program identifier.
pub use constants::ZK_TOKEN_PROOF_PROGRAM_ID;
/// One enumerable program identifier entry.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct ProgramIdEntry {
/// Stable lower snake case registry code.
pub name: &'static str,
/// Base58 Solana program identifier.
pub address: &'static str,
}
impl ProgramIdEntry {
/// Returns the stable lower snake case registry code.
pub const fn code(&self) -> &'static str {
return self.name;
}
/// Returns the Base58 Solana program identifier.
pub const fn program_id(&self) -> &'static str {
return self.address;
}
}
pub use programs::ProgramIdEntry;
/// Returns every program identifier currently registered by this crate.
pub fn entries() -> &'static [crate::ProgramIdEntry] {
return crate::PROGRAM_ID_ENTRIES;
}
/// Returns every program identifier currently registered by this crate.
pub fn registered_program_ids() -> &'static [crate::ProgramIdEntry] {
return crate::PROGRAM_ID_ENTRIES;
}
/// Returns every executable runtime-native, loader, precompile and historical native program identifier.
pub fn native_program_ids() -> &'static [crate::ProgramIdEntry] {
return crate::NATIVE_PROGRAM_ID_ENTRIES;
}
/// Returns native well-known accounts that are not executable programs.
pub fn native_well_known_account_ids() -> &'static [crate::ProgramIdEntry] {
return crate::NATIVE_WELL_KNOWN_ACCOUNT_ID_ENTRIES;
}
pub use programs::entries;
/// Finds one registered program or well-known account by exact Base58 identifier.
pub fn find_registered_program_id(
program_id: &str,
) -> std::option::Option<&'static crate::ProgramIdEntry> {
return crate::PROGRAM_ID_ENTRIES
.iter()
.find(|entry| return entry.address == program_id);
}
#[cfg(test)]
mod tests {
#[test]
fn registry_entries_are_unique_and_non_empty() {
let mut codes = std::collections::BTreeSet::new();
let mut program_ids = std::collections::BTreeSet::new();
for entry in crate::registered_program_ids() {
assert!(!entry.code().is_empty());
assert!(!entry.program_id().is_empty());
assert!(codes.insert(entry.code()));
assert!(program_ids.insert(entry.program_id()));
}
assert_eq!(crate::registered_program_ids().len(), 31);
}
#[test]
fn native_registry_contains_exactly_every_solana_core_surface() {
let codes = crate::native_program_ids()
.iter()
.map(crate::ProgramIdEntry::code)
.collect::<std::collections::BTreeSet<_>>();
assert!(codes.contains("vote"));
assert!(codes.contains("slashing"));
assert!(codes.contains("bpf_loader_deprecated"));
assert!(codes.contains("bpf_loader"));
assert!(codes.contains("bpf_loader_upgradeable"));
assert!(codes.contains("loader_v4"));
assert_eq!(codes.len(), 18);
assert_eq!(codes.len(), crate::native_program_ids().len());
}
#[test]
fn stake_config_is_a_well_known_account_not_an_executable_program() {
assert!(crate::native_well_known_account_ids().iter().any(|entry| {
return entry.program_id() == crate::STAKE_CONFIG_ACCOUNT_ID;
}));
assert!(!crate::native_program_ids().iter().any(|entry| {
return entry.program_id() == crate::STAKE_CONFIG_ACCOUNT_ID;
}));
}
#[test]
fn registry_lookup_finds_system_program() {
let entry = crate::find_registered_program_id(crate::SYSTEM_PROGRAM_ID);
assert_eq!(entry.map(crate::ProgramIdEntry::code), std::option::Option::Some("system"));
}
#[test]
fn compatibility_api_and_core_constants_are_complete() {
assert_eq!(crate::entries(), crate::registered_program_ids());
assert_eq!(crate::STAKE_CONFIG_PROGRAM_ID, crate::STAKE_CONFIG_ACCOUNT_ID);
let expected = [
crate::ADDRESS_LOOKUP_TABLE_PROGRAM_ID,
crate::COMPUTE_BUDGET_PROGRAM_ID,
crate::CONFIG_PROGRAM_ID,
crate::FEATURE_PROGRAM_ID,
crate::SYSTEM_PROGRAM_ID,
crate::VOTE_PROGRAM_ID,
crate::STAKE_PROGRAM_ID,
crate::SLASHING_PROGRAM_ID,
crate::ZK_ELGAMAL_PROOF_PROGRAM_ID,
crate::ZK_TOKEN_PROOF_PROGRAM_ID,
];
for program_id in expected {
assert!(crate::find_registered_program_id(program_id).is_some());
}
}
#[test]
fn spl_primitives_are_registered_without_joining_native_surfaces() {
let spl_program_ids = [
crate::SPL_MEMO_V1_PROGRAM_ID,
crate::SPL_MEMO_V3_PROGRAM_ID,
crate::SPL_MEMO_V4_PROGRAM_ID,
crate::SPL_TOKEN_PROGRAM_ID,
crate::SPL_TOKEN_2022_PROGRAM_ID,
crate::ASSOCIATED_TOKEN_PROGRAM_ID,
];
for program_id in spl_program_ids {
assert!(crate::find_registered_program_id(program_id).is_some());
assert!(
!crate::native_program_ids()
.iter()
.any(|entry| return entry.program_id() == program_id)
);
}
}
}
pub use programs::find_registered_program_id;
/// Returns every executable runtime-native, loader, precompile and historical native program identifier.
pub use programs::native_program_ids;
/// Returns native well-known accounts that are not executable programs.
pub use programs::native_well_known_account_ids;
/// Returns every program identifier currently registered by this crate.
pub use programs::registered_program_ids;

View File

@@ -0,0 +1,144 @@
// file: kb-program-ids/src/programs.rs
// version: 1
//! Enumerable canonical program registry.
/// One enumerable program identifier entry.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct ProgramIdEntry {
/// Stable lower snake case registry code.
pub name: &'static str,
/// Base58 Solana program identifier.
pub address: &'static str,
}
impl ProgramIdEntry {
/// Returns the stable lower snake case registry code.
pub const fn code(&self) -> &'static str {
return self.name;
}
/// Returns the Base58 Solana program identifier.
pub const fn program_id(&self) -> &'static str {
return self.address;
}
}
/// Returns every program identifier currently registered by this crate.
pub fn entries() -> &'static [crate::ProgramIdEntry] {
return crate::PROGRAM_ID_ENTRIES;
}
/// Returns every program identifier currently registered by this crate.
pub fn registered_program_ids() -> &'static [crate::ProgramIdEntry] {
return crate::PROGRAM_ID_ENTRIES;
}
/// Returns every executable runtime-native, loader, precompile and historical native program identifier.
pub fn native_program_ids() -> &'static [crate::ProgramIdEntry] {
return crate::NATIVE_PROGRAM_ID_ENTRIES;
}
/// Returns native well-known accounts that are not executable programs.
pub fn native_well_known_account_ids() -> &'static [crate::ProgramIdEntry] {
return crate::NATIVE_WELL_KNOWN_ACCOUNT_ID_ENTRIES;
}
/// Finds one registered program or well-known account by exact Base58 identifier.
pub fn find_registered_program_id(
program_id: &str,
) -> std::option::Option<&'static crate::ProgramIdEntry> {
return crate::PROGRAM_ID_ENTRIES
.iter()
.find(|entry| return entry.address == program_id);
}
#[cfg(test)]
mod tests {
#[test]
fn registry_entries_are_unique_and_non_empty() {
let mut codes = std::collections::BTreeSet::new();
let mut program_ids = std::collections::BTreeSet::new();
for entry in crate::registered_program_ids() {
assert!(!entry.code().is_empty());
assert!(!entry.program_id().is_empty());
assert!(codes.insert(entry.code()));
assert!(program_ids.insert(entry.program_id()));
}
assert_eq!(crate::registered_program_ids().len(), 32);
}
#[test]
fn native_registry_contains_exactly_every_solana_core_surface() {
let codes = crate::native_program_ids()
.iter()
.map(crate::ProgramIdEntry::code)
.collect::<std::collections::BTreeSet<_>>();
assert!(codes.contains("vote"));
assert!(codes.contains("slashing"));
assert!(codes.contains("bpf_loader_deprecated"));
assert!(codes.contains("bpf_loader"));
assert!(codes.contains("bpf_loader_upgradeable"));
assert!(codes.contains("loader_v4"));
assert_eq!(codes.len(), 18);
assert_eq!(codes.len(), crate::native_program_ids().len());
}
#[test]
fn stake_config_is_a_well_known_account_not_an_executable_program() {
assert!(crate::native_well_known_account_ids().iter().any(|entry| {
return entry.program_id() == crate::STAKE_CONFIG_ACCOUNT_ID;
}));
assert!(!crate::native_program_ids().iter().any(|entry| {
return entry.program_id() == crate::STAKE_CONFIG_ACCOUNT_ID;
}));
}
#[test]
fn registry_lookup_finds_system_program() {
let entry = crate::find_registered_program_id(crate::SYSTEM_PROGRAM_ID);
assert_eq!(entry.map(crate::ProgramIdEntry::code), std::option::Option::Some("system"));
}
#[test]
fn compatibility_api_and_core_constants_are_complete() {
assert_eq!(crate::entries(), crate::registered_program_ids());
assert_eq!(crate::STAKE_CONFIG_PROGRAM_ID, crate::STAKE_CONFIG_ACCOUNT_ID);
let expected = [
crate::ADDRESS_LOOKUP_TABLE_PROGRAM_ID,
crate::COMPUTE_BUDGET_PROGRAM_ID,
crate::CONFIG_PROGRAM_ID,
crate::FEATURE_PROGRAM_ID,
crate::SYSTEM_PROGRAM_ID,
crate::VOTE_PROGRAM_ID,
crate::STAKE_PROGRAM_ID,
crate::SLASHING_PROGRAM_ID,
crate::ZK_ELGAMAL_PROOF_PROGRAM_ID,
crate::ZK_TOKEN_PROOF_PROGRAM_ID,
];
for program_id in expected {
assert!(crate::find_registered_program_id(program_id).is_some());
}
}
#[test]
fn spl_primitives_are_registered_without_joining_native_surfaces() {
let spl_program_ids = [
crate::SPL_MEMO_V1_PROGRAM_ID,
crate::SPL_MEMO_V3_PROGRAM_ID,
crate::SPL_MEMO_V4_PROGRAM_ID,
crate::SPL_TOKEN_PROGRAM_ID,
crate::SPL_TOKEN_2022_PROGRAM_ID,
crate::SPL_TOKEN_2022_ELGAMAL_REGISTRY_PROGRAM_ID,
crate::ASSOCIATED_TOKEN_PROGRAM_ID,
];
for program_id in spl_program_ids {
assert!(crate::find_registered_program_id(program_id).is_some());
assert!(
!crate::native_program_ids()
.iter()
.any(|entry| return entry.program_id() == program_id)
);
}
}
}