v0.4.8-pre.010
This commit is contained in:
@@ -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 l’adaptateur `getAccountInfo` borne une réponse complète à `65536` octets ;
|
||||
- l’endpoint 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 l’inventaire et l’adaptation 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 d’exé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 qu’il 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 d’une lecture complète via l’adaptateur d’exé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 l’appel 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` lorsqu’il 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 d’absence 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 d’exé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 d’autres 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 lorsqu’elle possède une cible racine canonique.
|
||||
|
||||
## 9. Diagnostic Devnet du correctif suivant
|
||||
|
||||
La campagne réelle postérieure à l’activation 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 d’une 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 qu’une nouvelle autorité non nulle est fournie.
|
||||
|
||||
La campagne corrigée couvre donc toujours les neuf opérations, mais selon l’ordre suivant :
|
||||
|
||||
```text
|
||||
Buffer:
|
||||
Allocate -> Extend -> Write -> SetAuthority -> Trim -> Close
|
||||
|
||||
Metadata non canonique:
|
||||
Initialize -> SetData -> SetImmutable
|
||||
```
|
||||
|
||||
Le profil public Devnet de l’exemple 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.
|
||||
|
||||
Reference in New Issue
Block a user