>_ DevTrendsnl

Taal

Home

Talen

Secties

Frontend Backend Mobiel DevOps AI / ML GameDev Blockchain Embedded Beveiliging
Rust

Zo schrijf je slimme contracten voor Solana zonder gek te worden van boilerplate

Als je ooit geprobeerd hebt om programma's voor Solana in pure Rust te schrijven, herinner je je waarschijnlijk dat gevoel wanneer vijf regels bedrijfslogica vereisten dat je vijftig regels aan account-validatiecontroles, handmatige deserialisatie via Borsh en handtekeningvalidatie schreef. De volgorde van de sleutels in de transactie verkeerd — en je krijgt een runtime-fout die soms uren duurt om op te lossen.

In de Ethereum wereld zijn ontwikkelaars al lang gewend aan Solidity en kant-en-klare wrappers zoals Hardhat of Foundry. In Solana werd het overeenkomstige standaard Anchor — een framework dat alle routinematige werkzaamheden afhandelt: dataparsing, toegangscontrole en clientcodegeneratie.

Wat Anchor voor je doet

In essentie is Anchor een DSL (domain-specific language) bovenop Rust. Het verandert Solana's interne BPF-uitvoeringsmodel niet, maar verpakt low-level aanroepen in begrijpelijke declaratieve macros.

Wanneer je een programma met Anchor schrijft, lost het framework vier hoofd taken op:

  1. Serialisatie en deserialisatie van accountgegevens zonder handmatige unpack-method-aanroepen.
  2. Account-constraint-validatie rechtstreeks in de structuur-signatuur via attributen (eigenaarscontrole, handtekeningverificatie, geheugeninitialisatie).
  3. IDL (Interface Description Language) specificatie-assemblage — de equivalent van Ethereum's ABI.
  4. Aanmaak van kant-en-klare TypeScript en Rust clients voor interactie met het contract rechtstreeks vanaf de frontend of tests.

Hoe de code er in de praktijk uitziet

Laten we een klassiek counter-voorbeeld bekijken. In de pure Solana SDK zou je handmatig de byte-array InstructionData moeten parsen, account-slices moeten extraheren, is_signer moeten controleren op het adres van de beller, en het systeemprogramma-adres moeten valideren.

Zo ziet hetzelfde contract er in Anchor uit:

use anchor_lang::prelude::*;

declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");

#[program]
mod counter {
    use super::*;

    pub fn initialize(ctx: Context<Initialize>, start: u64) -> Result<()> {
        let counter = &mut ctx.accounts.counter;
        counter.authority = *ctx.accounts.authority.key;
        counter.count = start;
        Ok(())
    }

    pub fn increment(ctx: Context<Increment>) -> Result<()> {
        let counter = &mut ctx.accounts.counter;
        counter.count += 1;
        Ok(())
    }
}

#[derive(Accounts)]
pub struct Initialize<'info> {
    #[account(init, payer = authority, space = 48)]
    pub counter: Account<'info, Counter>,
    pub authority: Signer<'info>,
    pub system_program: Program<'info, System>,
}

#[derive(Accounts)]
pub struct Increment<'info> {
    #[account(mut, has_one = authority)]
    pub counter: Account<'info, Counter>,
    pub authority: Signer<'info>,
}

#[account]
pub struct Counter {
    pub authority: Pubkey,
    pub count: u64,
}

Het verschil is onmiddellijk duidelijk. Alle validatielogica is verplaatst naar de Initialize en Increment structuren.

Het #[account(init, payer = authority, space = 48)] attribuut vertelt de runtime: maak een nieuw account aan, wijs 48 bytes toe, en breng de huur aan de authority wallet.

Het #[account(mut, has_one = authority)] construct controleert automatisch dat het authority veld binnen de Counter structuur overeenkomt met het doorgegeven account authority, en dat dit account daadwerkelijk de transactie heeft ondertekend. Als er geen handtekening is of een andere wallet is doorgegeven, wordt de uitvoering afgebroken voordat de functie-body wordt betreden increment.

IDL en Frontend Zonder Hoofdpijn

Het meest handige in de Anchor-bundel is het IDL-bestand in JSON-formaat. De compiler stelt het automatisch samen bij het bouwen van het project.

De IDL beschrijft alle instructies, datastructuren en mogelijke aangepaste fouttypen van het programma. Op basis van dit bestand genereert de @anchor-lang/core bibliotheek een getypte interface voor JavaScript of TypeScript.

Je hoeft niet langer byte-offsets te onthouden bij het samenstellen van een transactie aan de clientzijde. Het aanroepen van een methode vanaf de frontend wordt een gewone functieaanroep:

await program.methods
  .increment()
  .accounts({
    counter: counterPubkey,
    authority: wallet.publicKey,
  })
  .rpc();

TypeScript zal fouten markeren als je vergeet een vereist account door te geven of het verkeerde argumenttype opgeeft.

Ingebouwde Fuzzing voor het Vinden van Kwetsbaarheden

In slimme contracten is de kosten van een fout te hoog, daarom speelt testen een speciale rol. De CLI bevat integratie met het Crucible-tool voor coverage-guided fuzzing testing.

Het anchor fuzz init commando genereert een test harness, en anchor fuzz run voert het uit met willekeurige invoergegevens, en probeert edge cases te vinden die leiden tot panics of ongeldige account-staten. Dit helpt niet voor de hand liggende overflows of gemiste controles op te vangen voordat je naar de testnet deployt.

# Инициализация фазз-тестов
anchor fuzz init program_name

# Запуск тестов в release-сборке
anchor fuzz run program_name test_name --release

Installatie en Aan de Slag

Voor het beheren van toolchain-versies hebben ontwikkelaars een speciaal hulpprogramma gemaakt genaamd AVM (Anchor Version Manager). Dit bespaart je versieconflicten tussen de Solana-compiler en het framework zelf, wanneer verschillende projecten verschillende sub-versies vereisen.

Het hulpprogramma wordt geïnstalleerd met een enkele regel:

curl -sSfL https://raw.githubusercontent.com/otter-sec/anchor/master/avm/install | sh

Na installatie kun je overschakelen naar nightly builds of specifieke releases vastzetten voor je workspaces:

avm nightly
avm nightly --disable

Wie heeft voordeel bij Anchor

Als je net begint met Solana-ontwikkeling, is starten zonder Anchor praktisch zinloos. Je zult weken bezig zijn met het opnieuw uitvinden van het wiel voor account-parsing en discriminator-validatie.

Het framework dekt de belangrijkste behoeften:

  • Geeft Rust backend-ontwikkelaars strikte typering en bescherming tegen veelvoorkomende validatie-kwetsbaarheidspatronen.
  • Geeft frontend-ontwikkelaars kant-en-klare TypeScript-typen en handige methoden voor het verzenden van transacties.

Het enige geval waarin Anchor overbodig zou kunnen lijken, is het schrijven van micro-programma's met extreme binaire grootte-optimalisatie (compute budget limit), waar letterlijk elke byte aan instructies telt. In alle andere scenario's is het de facto standaard die honderden uren werk bespaart.

Gerelateerde projecten