v0.4.8-pre.010

This commit is contained in:
2026-08-06 17:26:14 +02:00
parent b314bfc244
commit 3167297283
40 changed files with 2556 additions and 1125 deletions

View File

@@ -0,0 +1,129 @@
<!-- file: docs/audits/V0_4_8_PRE_010_METADATA_SOLANA_PROGRAM_DESKTOP_INTEGRATION_AUDIT.md -->
<!-- version: 4 -->
# Audit `0.4.8-pre.010` — structure Metadata et exécution Devnet
## Périmètre
La prerelease raccorde `demo_execution_metadata` à la campagne Devnet Solana Program Metadata réutilisable. Le correctif `pre.010-fix-001` traite trois écarts révélés pendant la validation réelle :
- la structure desktop ne distinguait pas explicitement les contrats communs, Metaplex Token Metadata et Solana Program Metadata ;
- le pipeline stateful demandait une lecture complète de `10 MiB`, alors que ladaptateur `getAccountInfo` borne une réponse complète à `65536` octets ;
- lendpoint public Devnet a renvoyé `429 Too Many Requests` pendant une seconde campagne rapprochée.
## Structure desktop normalisée
La surface Rust est séparée en trois modules :
```text
kb-app-demo-desktop/src/demo_execution_metadata.rs
kb-app-demo-desktop/src/demo_execution_metadata_metaplex_token_metadata.rs
kb-app-demo-desktop/src/demo_execution_metadata_solana_program.rs
```
`demo_execution_metadata.rs` contient uniquement les contrats partagés du panneau :
- options de profils Devnet ;
- payload de progression Metadata ;
- observer Metadata commun aux workflows Metaplex et Solana Program Metadata.
Le module Metaplex contient les contrats, préparateurs et commandes propres à `metadata.metaplex_token_metadata`. Le module Solana Program Metadata contient linventaire et ladaptation de la campagne `metadata.solana_program_metadata`.
Les types et commandes Tauri Metaplex portent désormais explicitement le segment `metaplex_token_metadata`.
## Progression et verrou dexécution
Le workflow Metaplex réutilisait auparavant `DemoExecutionSolanaCoreObserver`, ce qui ciblait la fenêtre `demo_execution_solana_core`. Les deux workflows Metadata utilisent désormais `DemoExecutionMetadataObserver`, qui émet exclusivement vers :
```text
window = demo_execution_metadata
event = demo-execution-metadata-progress
```
Le garde RAII partagé est déplacé dans `demo_devnet_common.rs` sous le nom `DemoExecutionRunGuard`. Son identité ne dépend plus de Solana Core alors quil protège également les exécutions SPL et Metadata.
## Borne des lectures stateful
Deux limites distinctes sont conservées :
- `kb_lib::DC_METADATA_SPM_MAX_ACCOUNT_BYTES = 10 MiB` : capacité défensive du décodeur pour des octets déjà disponibles, notamment offline ou via un futur lecteur par tranches ;
- `kb_onchain_transport::MAX_COMPLETE_ACCOUNT_DATA_BYTES = 65536` : maximum actuel dune lecture complète via ladaptateur dexécution `getAccountInfo`.
`kb_pipeline::MAX_SOLANA_PROGRAM_METADATA_STATEFUL_ACCOUNT_BYTES` est alignée sur la seconde limite. Une lecture complète ne peut donc plus être construite avec une valeur que le transport refusera avant lappel RPC.
## Résilience aux limites RPC
`kb-onchain-transport` réessaie désormais les réponses suivantes :
- statut HTTP `429` ;
- erreur JSON-RPC de code `429`.
Le retry est borné à quatre tentatives supplémentaires. Le délai :
1. utilise `Retry-After` lorsquil contient un nombre de secondes ;
2. utilise sinon `pause_after_rate_limit_ms` du rôle compatible ;
3. applique un backoff exponentiel plafonné à `60000 ms`.
Le même objet JSON-RPC est réutilisé. Pour `sendTransaction`, la transaction signée et sa signature restent donc identiques pendant les retries.
## Validation attendue
Après application du correctif :
```bash
cargo fmt --all
cargo check --workspace
cargo clippy --all-targets
python3 scripts/audit_rust_workspace_rules.py
cargo test -p kb-onchain-transport
cargo test -p kb-pipeline
cargo test -p kb-app-demo-desktop
```
La campagne Devnet doit ensuite être relancée une seule fois. Les résultats attendus sont :
- aucun rejet local sur `max_data_bytes` ;
- retry visible et borné en cas de `429` ;
- deux préfinancements confirmés ;
- neuf opérations confirmées ;
- snapshots stateful présents, sauf preuve dabsence après `Close`.
## 8. Correctif de débit HTTP et cible de logging
La campagne Devnet a montré que les limites de rôle existaient dans la configuration, mais nétaient pas appliquées par le client HTTP générique utilisé par les RPC dexécution. Le backfill disposait de son propre pacer ; cette protection ne couvrait pas les lectures stateful, simulations, soumissions et confirmations du desktop.
Le client HTTP applique désormais avant chaque tentative :
1. un token bucket partagé fondé sur `requests_per_second` et `burst_capacity` ;
2. un sémaphore partagé fondé sur `max_concurrent_requests` ;
3. le rôle exact retenu par `HttpEndpointPool` lorsque plusieurs rôles acceptent le même type de requête ;
4. un cooldown partagé après une réponse HTTP ou JSON-RPC `429`.
Le retry borné reste nécessaire : un endpoint public peut imposer un quota dynamique ou partagé avec dautres processus, adresses IP ou utilisateurs. Un warning `retry_http_json_rpc_after_rate_limit` signifie que la seconde ligne de défense a été activée ; il ne signifie pas que la requête a été perdue.
La fixture Solana Program Metadata réutilise en outre la cible racine `kb-pipeline-demo-scenarios`. La crate ne déclare donc plus deux constantes de tracing lorsquelle possède une cible racine canonique.
## 9. Diagnostic Devnet du correctif suivant
La campagne réelle postérieure à lactivation des limiteurs confirme que les réponses `429` sont récupérées : chaque warning observé est suivi du même `request_id` avec `retry_index = 1` et dune réponse `200 OK`. Elles ralentissent la campagne mais ne constituent pas sa cause terminale.
Léchec reproductible intervient sur `SetAuthority` après `Initialize` et `SetData` :
```text
InstructionError[0] = InvalidAccountData
```
La fixture initialisait un compte Metadata non canonique puis tentait de réaffirmer son autorité. Le processeur officiel refuse explicitement `SetAuthority` sur un compte Metadata dont le drapeau `canonical` est faux. La même opération est en revanche autorisée sur un Buffer non canonique dès lors quune nouvelle autorité non nulle est fournie.
La campagne corrigée couvre donc toujours les neuf opérations, mais selon lordre suivant :
```text
Buffer:
Allocate -> Extend -> Write -> SetAuthority -> Trim -> Close
Metadata non canonique:
Initialize -> SetData -> SetImmutable
```
Le profil public Devnet de lexemple est également abaissé à `3 r/s` pour les lectures et `1 r/s` pour les transactions. Les anciens fichiers de configuration locaux doivent être ajustés manuellement.