# Blockchain-nativ

> Eine Blockchain-native Anwendung besteht aus denselben Komponenten wie die Anwendung, die Sie heute bauen, mit einem Austausch auf jeder Schicht. Hier finden Sie jeden Austausch und ein Hauptbuch, auf beide Arten gebaut.

Eine Blockchain-native Anwendung ist wirtschaftliche Aktivität, deren Abwicklung, Verwahrung und Regeln von Grund auf on-chain liegen, und kein herkömmliches Geschäft, an das seitlich ein Token angeheftet ist. Das klingt nach einer anderen Art von Engineering. Der Unterschied ist kleiner, als es klingt.

Jede Komponente des Stacks, den Sie heute bauen, hat ein Gegenstück. Das Gegenstück erfüllt dieselbe Aufgabe mit einer Änderung: Worauf man bisher vertrauen musste, das wird jetzt bewiesen. Apogee existiert, um diese Änderung so günstig zu machen, dass sie zum Standard wird.

## Der Wandel in einem Satz

In einer herkömmlichen Anwendung ist der Server die Autorität: Er hält die Daten, wendet die Regeln an und meldet das Ergebnis. In einer Blockchain-nativen Anwendung hält die Chain ein Commitment auf die Daten, die Regeln sind ein Programm, das jeder über seinen Digest benennen kann, und ein Ergebnis wird nur mit einem Beweis akzeptiert, dass dieses Programm es erzeugt hat.

Der Betreiber verschwindet nicht. Jemand führt weiterhin das Programm aus, speichert die Daten und beantwortet Anfragen. Was verschwindet, ist die Notwendigkeit, ihm zu glauben.

## Schicht für Schicht

| Schicht | Herkömmliche Anwendung | Blockchain-nativ, auf Apogee | Was bleibt |
| --- | --- | --- | --- |
| Geschäftslogik | Ein Dienst, den Sie auf selbst betriebenen Servern bereitstellen | Ein Gastprogramm (Guest): `no_std`-Rust, nach RISC-V kompiliert und bei jedem Lauf bewiesen | Sie schreiben weiterhin Funktionen über Daten. Das Programm wird über seine Identität benannt, einen Digest seines Codes und seiner Konfiguration. |
| Datenspeicher | SQL-Tabellen, ein Key-Value-Store | Die Daten bleiben off-chain; die Chain speichert eine Zustandswurzel, einen einzigen Hash, der einen Snapshot aller Daten zusammenfasst | Ein Snapshot, den Sie mit 32 Byte benennen und gegen den Sie alles prüfen können. |
| Leseabfrage | `SELECT balance FROM accounts WHERE id = ?` | Ein Inklusionsbeweis, ein Merkle-Pfad, den das Gastprogramm gegen die Wurzel prüft | Eine Abfrage liefert weiterhin eine Zeile. Die Zeile kommt jetzt mit einem Nachweis, und das Gastprogramm weist jede Zeile zurück, deren Prüfung fehlschlägt. |
| Schreiben | `UPDATE …; COMMIT;` | Ein Zustandsübergang: Das Gastprogramm berechnet die neue Wurzel und veröffentlicht sie | Commit heißt weiterhin „dauerhaft machen“. Jetzt bedeutet es, dass ein Contract die gespeicherte Wurzel fortschreibt. |
| Anfrage | Der Body einer HTTP-Anfrage | Die öffentliche Eingabe, die der Beweis bindet | Eingaben hinein, Ausgaben heraus. |
| Große Nutzdaten | Uploads, per Join verknüpfte Zeilen, abgerufene Dokumente | Hilfsdaten (Advice): Bytes, die der Prover liefert und die das Gastprogramm gegen etwas prüft, das der Beweis bindet | Große Daten per Referenz übergeben und prüfen, was angekommen ist. |
| Antwort | Ein JSON-Body | Das Journal: die öffentliche Ausgabe, durch den Beweis gebunden | Jeder kann die Antwort lesen und weiß, dass sie vom Programm stammt. |
| Authentifizierung | Sessions, Tokens, Passwörter | Signaturen, im Gastprogramm verifiziert; die secp256k1-Recovery läuft auf delegierter Körper- und Kurvenarithmetik | Identität ist ein Schlüssel, und Autorisierung ist eine Prüfung, die Sie im Quellcode nachlesen können. |
| Kryptografie-Bibliotheken | `sha2`, `ring`, OpenSSL | `guest_sdk::keccak256`, `sha256`, `ec_add`, jeweils an einen eigenen Schaltkreis weitergeleitet | Dieselben Aufrufe, für einen Bruchteil der Zyklen. |
| Release | Ein Binary ausrollen, und das Verhalten ändert sich sofort | Die neue Programmidentität beim Verifier-Contract registrieren | Releases werden explizit: Ein neuer Build ist eine neue Identität, die der Contract akzeptieren muss. |
| Skalierung | Mehr Server, geshardete Datenbanken | Eine Ausführung, zerlegt in Shards, die parallel bewiesen werden, und durch Rekursion zu einem einzigen Beweis gefaltet | Der Durchsatz entsteht durch Prover, die nebeneinander arbeiten, während die Chain weiterhin einen einzigen Beweis prüft. |
| Audit | Logs und Bescheinigungen, die man Ihnen glauben muss | Der Beweis und sein Journal | Gewissheit beruht nicht mehr auf Reputation, sondern auf Verifikation. |

Die mittlere Spalte ist das, woraus eine Blockchain-native Anwendung besteht. Apogee liefert die Maschinerie darunter: die RISC-V-Maschine, die Schaltkreise, die Commitments, die Rekursion und den Verifier-Contract. Nichts davon taucht in Ihrem Programm auf.

## Was sich nicht ändert

- **Sie schreiben weiterhin gewöhnliches Rust.** Structs, Enums, Traits, Iteratoren, `Vec`, `BTreeMap` und jedes Crate, das ohne `std` baut. Es gibt keine Schaltkreissprache zu lernen.
- **Sie testen weiterhin auf Ihrem Laptop.** Der übliche Aufbau legt die Anwendungslogik in eine `no_std`-Bibliothek, die auf dem Host unter `cargo test` genau so läuft wie im Gastprogramm. Siehe [Ein Gastprogramm schreiben](https://apogee.gweb3networks.com/docs/launch/write#host-first).
- **Sie denken weiterhin in Zustand, Anfragen und Antworten.** Die Formen bleiben gleich; nur ihre Garantien ändern sich.
- **Deterministischer Code bleibt deterministisch.** Guter Backend-Code vermeidet ohnehin versteckte Eingaben. Die VM macht daraus eine absolute Regel.

## Was sich ändert

- **Keine Außenwelt.** Ein Gastprogramm hat keine Uhr, keinen Zufall, kein Netzwerk und keine Dateien. Alles, was es weiß, kommt als öffentliche Eingabe oder als Hilfsdaten an, und eine Anfrage nach Daten des Hosts ist ein Aufruf, den kein Beweis zulässt.
- **Jeder Befehl hat einen Preis.** Jeder ausgeführte Befehl wird zu einer bewiesenen Zeile. Kopien, Allokationen und Leerlaufschleifen kosten Beweiszeit; die alte Disziplin des Zyklenzählens kehrt also zurück.
- **Gelieferte Daten werden geprüft, nicht geglaubt.** Hilfsdaten wählt der Prover. Ein Gastprogramm prüft sie gegen etwas, das der Beweis bindet, bevor irgendetwas daraus Abgeleitetes veröffentlicht wird.
- **Ausgaben sind klein und öffentlich.** Das Journal fasst höchstens 16.380 Byte. Ein großes Ergebnis wird als Digest veröffentlicht.
- **Nichts ist verborgen.** Beweise von Apogee v1.0.0 sind succinct, aber nicht zero-knowledge. Ein Gastprogramm darf keine Geheimnisse enthalten.

## Ein Hauptbuch, auf beide Arten gebaut

Eine Einzahlung auf einen Kontostand: die kleinste Zustandsänderung, die einen Beweis lohnt.

### Die herkömmliche Version

```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
```

Die Nutzer vertrauen darauf, dass der Betreiber genau dies ausgeführt hat, gegen die echte Tabelle, und dass er das Ergebnis ehrlich meldet.

### Die Blockchain-native Version

Die Konten liegen in einem binären Merkle-Baum, dessen Blätter `keccak256(account ‖ balance)` sind. Ein Contract speichert die Wurzel. Das Gastprogramm erhält die alte Wurzel und die Anfrage als öffentliche Eingabe, den Kontostand und den Merkle-Pfad des Kontos als Hilfsdaten, prüft den Pfad und veröffentlicht die alte und die neue Wurzel.

```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());
}
```

Lesen Sie es neben dem SQL. Aus `SELECT … FOR UPDATE` wurde ein Merkle-Pfad, der gegen die Wurzel geprüft wird. Aus `UPDATE` wurde ein neues Blatt auf demselben Pfad. Aus `COMMIT` wurden vier Aufrufe von `commit`, die das Journal schreiben, das der Beweis binden wird. Der Kontostand kam vom Prover, und das ist in Ordnung: Ein Kontostand, den die Wurzel nicht festlegt, scheitert an der Prüfung, und der Lauf endet mit Exit-Status 2.

Der Contract, dem die Wurzel gehört, akzeptiert einen Übergang nur mit einem Beweis, dass dieses Programm ihn erzeugt hat und mit Exit-Status 0 endete:

```solidity title="Ledger.sol (Skizze)"
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]
> Dies ist eine Skizze, um die Form zu zeigen, kein Contract für den Produktivbetrieb. Ein echtes Deployment verarbeitet einen Stapel von Anfragen pro Beweis, den das Gastprogramm zu einem einzigen Übergang zusammenfasst, und legt den Verifier auf das richtige Programm und die richtigen Längen der öffentlichen Werte fest. [On-Chain abwickeln](https://apogee.gweb3networks.com/docs/launch/on-chain) behandelt den bereitgestellten Verifier, seinen Schlüssel und seine Zeremonie.

## Das Modell in drei Zeilen

1. Die Chain hält eine Wurzel.
2. Das Gastprogramm beweist den Übergang.
3. Der Contract schreibt die Wurzel fort.

Alles andere, von den Shards und Schaltkreisen bis zur Rekursion und zum Decider, übernimmt Apogee. Das ist die Abstraktion: ein Programm, seine Eingabe und seine Ausgabe sowie ein Beweis, der sie miteinander verbindet.

## Nächste Schritte

- [Schnellstart](https://apogee.gweb3networks.com/docs/launch/quickstart): Vom leeren Crate zum verifizierten Beweis.

- [Eingaben, Hilfsdaten und Journal](https://apogee.gweb3networks.com/docs/launch/io): Die drei Speicherbereiche, mit denen jedes Gastprogramm arbeitet.

- [Programmierleitfaden für Gastprogramme](https://apogee.gweb3networks.com/docs/launch/guide): Die Gewohnheiten, die ein Gastprogramm korrekt, beweisbar und günstig halten.
