# Natif blockchain

> Une application native blockchain est faite des mêmes composants que celle que vous construisez aujourd’hui, avec un remplacement à chaque couche. Voici chacun de ces remplacements, et un registre construit des deux façons.

Une application native blockchain est une activité économique dont le règlement, la garde des actifs et les règles sont sur la chaîne par construction, et non une entreprise conventionnelle à laquelle on aurait greffé un jeton. Cela ressemble à une tout autre ingénierie. L’écart est moindre qu’il n’y paraît.

Chaque composant de la pile que vous construisez aujourd’hui a son équivalent. Cet équivalent fait le même travail, à un changement près : ce qui relevait de la confiance est désormais prouvé. Apogee existe pour rendre ce changement assez peu coûteux pour qu’il devienne la norme.

## Le changement en une phrase

Dans une application conventionnelle, le serveur fait autorité : il détient les données, applique les règles et rapporte le résultat. Dans une application native blockchain, la chaîne détient un engagement sur les données, les règles sont un programme que chacun peut désigner par son condensé, et un résultat n’est accepté qu’accompagné d’une preuve que ce programme l’a produit.

L’opérateur ne disparaît pas. Quelqu’un exécute toujours le programme, stocke les données et répond aux requêtes. Ce qui disparaît, c’est la nécessité de le croire.

## Couche par couche

| Couche | Application conventionnelle | Native blockchain, sur Apogee | Ce qui se transpose |
| --- | --- | --- | --- |
| Logique métier | Un service que vous déployez sur des serveurs que vous gérez | Un programme invité : du Rust `no_std` compilé pour RISC-V et prouvé à chaque exécution | Vous écrivez toujours des fonctions sur des données. Le programme est désigné par son identité, un condensé de son code et de sa configuration. |
| Stockage des données | Des tables SQL, un stockage clé-valeur | Les données restent hors chaîne; la chaîne stocke une racine d’état, un hachage unique qui résume un instantané de l’ensemble | Un instantané désignable en 32 octets, par rapport auquel tout peut être vérifié. |
| Requête de lecture | `SELECT balance FROM accounts WHERE id = ?` | Une preuve d’inclusion, un chemin de Merkle, que le programme invité vérifie par rapport à la racine | Une requête renvoie toujours une ligne. La ligne arrive désormais accompagnée de justificatifs, et le programme invité refuse toute ligne qui ne passe pas la vérification. |
| Écriture | `UPDATE …; COMMIT;` | Une transition d’état : le programme invité calcule la nouvelle racine et la publie | Valider signifie toujours « rendre durable ». Cela signifie désormais qu’un contrat fait avancer la racine stockée. |
| Requête | Le corps d’une requête HTTP | L’entrée publique, que la preuve lie | Les entrées entrent, les sorties sortent. |
| Charge utile volumineuse | Téléversements, lignes jointes, documents récupérés | Les données auxiliaires (*advice*) : des octets que le prouveur fournit et que le programme invité vérifie par rapport à quelque chose que la preuve lie | Passez les données volumineuses par référence et vérifiez ce qui est arrivé. |
| Réponse | Un corps JSON | Le journal : la sortie publique, liée par la preuve | N’importe qui peut lire la réponse et savoir qu’elle provient du programme. |
| Authentification | Sessions, jetons, mots de passe | Des signatures vérifiées dans le programme invité; la récupération de clé secp256k1 s’exécute sur l’arithmétique de corps et de courbe déléguée | L’identité est une clé, et l’autorisation est une vérification que vous pouvez lire dans le code source. |
| Bibliothèques cryptographiques | `sha2`, `ring`, OpenSSL | `guest_sdk::keccak256`, `sha256`, `ec_add`, chacune acheminée vers un circuit dédié | Les mêmes appels, pour une fraction des cycles. |
| Mise en production | Vous poussez un binaire, et le comportement change aussitôt | Vous enregistrez la nouvelle identité du programme auprès du contrat vérificateur | Les mises en production deviennent explicites : une nouvelle compilation est une nouvelle identité que le contrat doit accepter. |
| Mise à l’échelle | Plus de serveurs, des bases de données partitionnées | Une exécution découpée en shards prouvés en parallèle, repliés par récursion en une seule preuve | Le débit vient de prouveurs qui travaillent côte à côte, tandis que la chaîne ne vérifie toujours qu’une seule preuve. |
| Audit | Des journaux d’événements et des attestations que vous demandez de croire sur parole | La preuve et son journal | L’assurance passe de la réputation à la vérification. |

La colonne centrale est ce dont est faite une application native blockchain. Apogee fournit la machinerie qui se trouve en dessous : la machine RISC-V, les circuits, les engagements, la récursion et le contrat vérificateur. Rien de tout cela n’apparaît dans votre programme.

## Ce qui ne change pas

- **Vous écrivez toujours du Rust ordinaire.** Structures, énumérations, traits, itérateurs, `Vec`, `BTreeMap`, et toute crate qui compile sans `std`. Il n’y a aucun langage de circuits à apprendre.
- **Vous testez toujours sur votre ordinateur portable.** L’organisation habituelle place la logique applicative dans une bibliothèque `no_std` qui s’exécute sur l’hôte, sous `cargo test`, exactement comme elle s’exécute dans le programme invité. Voir [Écrire un programme invité](https://apogee.gweb3networks.com/docs/launch/write#host-first).
- **Vous raisonnez toujours en termes d’état, de requêtes et de réponses.** Les formes sont les mêmes; seules leurs garanties changent.
- **Le code déterministe reste déterministe.** Un bon code côté serveur évite déjà les entrées cachées. La VM rend cette règle absolue.

## Ce qui change

- **Aucun monde ambiant.** Un programme invité n’a ni horloge, ni aléa, ni réseau, ni fichiers. Tout ce qu’il sait lui parvient comme entrée publique ou comme données auxiliaires, et une demande de données à l’hôte est un appel qu’aucune preuve n’admet.
- **Chaque instruction a un prix.** Chaque instruction exécutée devient une ligne prouvée. Les copies, les allocations et les boucles inutiles coûtent du temps de preuve : la vieille discipline du décompte des cycles fait son retour.
- **Les données fournies sont vérifiées, pas crues sur parole.** Les données auxiliaires sont choisies par le prouveur. Un programme invité les vérifie par rapport à quelque chose que la preuve lie avant que quoi que ce soit qui en dérive ne soit publié.
- **Les sorties sont petites et publiques.** Le journal contient au plus 16 380 octets. Un résultat volumineux est publié sous forme de condensé.
- **Rien n’est caché.** Les preuves d’Apogee v1.0.0 sont succinctes, pas à divulgation nulle de connaissance. Un programme invité ne doit détenir aucun secret.

## Un registre, construit des deux façons

Un dépôt sur le solde d’un compte : le plus petit changement d’état qui vaille la peine d’être prouvé.

### La version conventionnelle

```sql
BEGIN;
SELECT balance FROM accounts WHERE id = $1 FOR UPDATE;    -- read
UPDATE accounts SET balance = balance + $2 WHERE id = $1;  -- write
COMMIT;                                                     -- make it durable
```

Les utilisateurs font confiance à l’opérateur pour avoir exécuté exactement ceci, sur la vraie table, et pour rapporter le résultat honnêtement.

### La version native blockchain

Les comptes résident dans un arbre de Merkle binaire dont les feuilles sont `keccak256(account ‖ balance)`. Un contrat stocke la racine. Le programme invité reçoit l’ancienne racine et la requête comme entrée publique, reçoit le solde du compte et son chemin de Merkle comme données auxiliaires, vérifie le chemin, puis publie l’ancienne et la nouvelle racine.

```rust title="guests/ledger/src/main.rs"
#![no_std]
#![no_main]

guest_sdk::entry!(main);

const DEPTH: usize = 20; // room for 2^20 accounts

/// A leaf commits to one account's balance.
fn leaf(account: &[u8; 20], balance: u64) -> [u8; 32] {
    let mut bytes = [0u8; 28];
    bytes[..20].copy_from_slice(account);
    bytes[20..].copy_from_slice(&balance.to_le_bytes());
    guest_sdk::keccak256(&bytes)
}

/// Fold a leaf up its Merkle path; bit `level` of `index` says whether the
/// node is a right child at that level.
fn root_of(mut node: [u8; 32], index: u32, path: &[[u8; 32]; DEPTH]) -> [u8; 32] {
    let mut pair = [0u8; 64];
    for (level, sibling) in path.iter().enumerate() {
        let (left, right) = if (index >> level) & 1 == 0 { (&node, sibling) } else { (sibling, &node) };
        pair[..32].copy_from_slice(left);
        pair[32..].copy_from_slice(right);
        node = guest_sdk::keccak256(&pair);
    }
    node
}

/// Public input: old_root (32) ‖ account (20) ‖ amount (8, LE)
/// Advice:       balance (8, LE) ‖ index (4, LE) ‖ path (DEPTH × 32)
/// Journal:      old_root ‖ new_root ‖ account ‖ amount
fn main() {
    let input = guest_sdk::public_input();
    let advice = guest_sdk::advice();
    if input.len() != 60 || advice.len() != 12 + 32 * DEPTH {
        guest_sdk::exit(1);
    }
    let old_root: [u8; 32] = input[..32].try_into().unwrap();
    let account: [u8; 20] = input[32..52].try_into().unwrap();
    let amount = u64::from_le_bytes(input[52..60].try_into().unwrap());

    let balance = u64::from_le_bytes(advice[..8].try_into().unwrap());
    let index = u32::from_le_bytes(advice[8..12].try_into().unwrap());
    let mut path = [[0u8; 32]; DEPTH];
    for (i, sibling) in path.iter_mut().enumerate() {
        sibling.copy_from_slice(&advice[12 + 32 * i..12 + 32 * (i + 1)]);
    }

    // The query: the balance the prover supplied is the one the root commits to.
    if root_of(leaf(&account, balance), index, &path) != old_root {
        guest_sdk::exit(2);
    }
    // The write: the same path with the new leaf gives the new root.
    let Some(new_balance) = balance.checked_add(amount) else { guest_sdk::exit(3) };
    let new_root = root_of(leaf(&account, new_balance), index, &path);

    // The commit: publish the transition for the contract to apply.
    guest_sdk::commit(&old_root);
    guest_sdk::commit(&new_root);
    guest_sdk::commit(&account);
    guest_sdk::commit(&amount.to_le_bytes());
}
```

Lisez-le en regard du SQL. `SELECT … FOR UPDATE` est devenu un chemin de Merkle vérifié par rapport à la racine. `UPDATE` est devenu une nouvelle feuille sur le même chemin. `COMMIT` est devenu quatre appels à `commit`, qui écrivent le journal que la preuve liera. Le solde vient du prouveur, et cela ne pose aucun problème : un solde sur lequel la racine ne s’engage pas échoue à la vérification, et l’exécution se termine avec le statut 2.

Le contrat qui détient la racine n’accepte une transition qu’accompagnée d’une preuve que ce programme l’a produite et s’est terminé avec le statut 0 :

```solidity title="Ledger.sol (esquisse)"
interface IApogeeVerifier {
    function verify(bytes calldata input, bytes calldata output, uint256 exitStatus,
                    uint256[10] calldata proof, uint256[] calldata points) external view returns (bool);
}

contract Ledger {
    IApogeeVerifier public immutable verifier;
    bytes32 public root;

    constructor(IApogeeVerifier v, bytes32 genesis) { verifier = v; root = genesis; }

    function apply(bytes calldata input, bytes calldata journal,
                   uint256[10] calldata proof, uint256[] calldata points) external {
        require(verifier.verify(input, journal, 0, proof, points), "proof");
        require(bytes32(journal[0:32]) == root, "stale root");
        root = bytes32(journal[32:64]);
    }
}
```

> [!NOTE]
> Ceci est une esquisse destinée à montrer la forme, pas un contrat de production. Un déploiement réel traite un lot de requêtes par preuve, que le programme invité replie en une seule transition, et rattache le vérificateur au bon programme et aux bonnes longueurs de valeurs publiques. [Régler sur la chaîne](https://apogee.gweb3networks.com/docs/launch/on-chain) traite du vérificateur déployé, de sa clé et de sa cérémonie.

## Le modèle en trois lignes

1. La chaîne détient une racine.
2. Le programme invité prouve la transition.
3. Le contrat fait avancer la racine.

Tout le reste, des shards et des circuits à la récursion et au décideur, relève d’Apogee. Voilà l’abstraction : un programme, son entrée et sa sortie, et une preuve qui les relie.

## Pour la suite

- [Démarrage rapide](https://apogee.gweb3networks.com/docs/launch/quickstart): D’une crate vide à une preuve vérifiée.

- [Entrées, données auxiliaires et journal](https://apogee.gweb3networks.com/docs/launch/io): Les trois régions mémoire avec lesquelles travaille tout programme invité.

- [Guide de programmation des programmes invités](https://apogee.gweb3networks.com/docs/launch/guide): Les habitudes qui gardent un programme invité correct, prouvable et peu coûteux.
