Solana accountmodel
Op Solana wordt alle data opgeslagen in wat "accounts" worden genoemd. Je kunt data op Solana zien als een openbare database met een enkele "Accounts"-tabel, waarbij elke invoer in deze tabel een "account" is. Elk Solana-account deelt hetzelfde basis Account type.
Accounts
Belangrijke punten
- Accounts kunnen maximaal 10MiB aan data opslaan, die ofwel uitvoerbare programmacode of programmastatus bevat.
- Accounts vereisen een rent deposit in lamports (SOL) dat evenredig is aan de hoeveelheid opgeslagen data, en je kunt het volledig terugkrijgen wanneer je het account sluit.
- Elk account heeft een programma owner. Alleen het programma dat eigenaar is van een account kan de data wijzigen of het lamport-saldo verminderen. Maar iedereen kan het saldo verhogen.
- Sysvar accounts zijn speciale accounts die de netwerkclusterstatus opslaan.
- Program accounts slaan de uitvoerbare code van smart contracts op.
- Data accounts worden gemaakt door programma's om programmastatus op te slaan en te beheren.
Account
Elk account op Solana heeft een uniek 32-byte adres, vaak weergegeven als een
base58 gecodeerde string (bijv. vines1vzrYbzLMRdu58ou5XTby4qAqVRLmqo36NKPTg
).
De relatie tussen het account en zijn adres werkt als een sleutel-waarde paar, waarbij het adres de sleutel is om de bijbehorende on-chain data van het account te lokaliseren. Het accountadres fungeert als de "unieke ID" voor elke invoer in de "Accounts"-tabel.
Account Adres
De meeste Solana-accounts gebruiken een Ed25519 publieke sleutel als hun adres.
import { generateKeyPairSigner } from "@solana/kit";// Kit does not enable extractable private keysconst keypairSigner = await generateKeyPairSigner();console.log(keypairSigner);
Hoewel publieke sleutels vaak worden gebruikt als account-adressen, ondersteunt Solana ook een functie genaamd Program Derived Addresses (PDA's). PDA's zijn speciale adressen die je deterministisch kunt afleiden van een programma-ID en optionele inputs (seeds).
import { Address, getProgramDerivedAddress } from "@solana/kit";const programAddress = "11111111111111111111111111111111" as Address;const seeds = ["helloWorld"];const [pda, bump] = await getProgramDerivedAddress({programAddress,seeds});console.log(`PDA: ${pda}`);console.log(`Bump: ${bump}`);
Account type
Accounts hebben een maximale grootte van 10MiB en elk account op Solana deelt hetzelfde basis Account type.
Account Type
Elk account op Solana heeft de volgende velden.
pub struct Account {/// lamports in the accountpub lamports: u64,/// data held in this account#[cfg_attr(feature = "serde", serde(with = "serde_bytes"))]pub data: Vec<u8>,/// the program that owns this account. If executable, the program that loads this account.pub owner: Pubkey,/// this account's data contains a loaded program (and is now read-only)pub executable: bool,/// the epoch at which this account will next owe rentpub rent_epoch: Epoch,}
Lamports veld
Het saldo van het account in lamports, de kleinste eenheid van SOL (1 SOL = 1
miljard lamports). Het SOL-saldo van een account is het bedrag in het lamports
veld omgerekend naar SOL.
Solana-accounts moeten een minimaal lamport-saldo hebben dat evenredig is aan de hoeveelheid gegevens die op het account is opgeslagen (in bytes). Dit minimumsaldo wordt "rent" genoemd.
Het lamport-saldo dat in het account is opgeslagen, kan volledig worden teruggevorderd wanneer het account wordt gesloten.
Data veld
Een byte-array die willekeurige gegevens voor een account opslaat. Het gegevensveld wordt gewoonlijk "account data" genoemd.
- Voor program accounts (smart contracts) bevat dit veld ofwel de uitvoerbare programmacode zelf of het adres van een ander account dat de uitvoerbare programmacode opslaat.
- Voor niet-uitvoerbare accounts slaat dit meestal de status op die bedoeld is om uit te lezen.
Het lezen van gegevens uit een Solana-account omvat twee stappen:
- Haal het account op met behulp van het adres (publieke sleutel)
- Deserialiseer het gegevensveld van het account van ruwe bytes naar de juiste gegevensstructuur, die wordt gedefinieerd door het programma dat eigenaar is van het account
Owner-veld
De programma-ID (publieke sleutel) van het programma dat eigenaar is van dit account.
Elk Solana-account heeft een aangewezen programma als eigenaar. Alleen het programma dat eigenaar is van een account kan de gegevens van het account wijzigen of het lamports- saldo verminderen.
De instructies die in een programma zijn gedefinieerd, bepalen hoe de gegevens en het lamports-saldo van het account kunnen worden gewijzigd.
Executable-veld
Dit veld geeft aan of een account een uitvoerbaar programma is.
- Als
true
, is het account een uitvoerbaar Solana-programma. - Als
false
, is het account een gegevensaccount dat status opslaat.
Voor uitvoerbare accounts bevat het owner
veld de programma-ID van een
loader-programma. Loader-programma's zijn ingebouwde programma's die
verantwoordelijk zijn voor het laden en beheren van uitvoerbare
programma-accounts.
Rent Epoch-veld
Het rent_epoch
veld is een verouderd veld dat niet meer wordt gebruikt.
Oorspronkelijk hield dit veld bij wanneer een account rent (in lamports) zou moeten betalen om zijn gegevens op het netwerk te behouden. Dit mechanisme voor het innen van rent is echter inmiddels verouderd.
Rent
Om gegevens on-chain op te slaan, moeten accounts ook een lamport (SOL) saldo aanhouden dat evenredig is aan de hoeveelheid opgeslagen gegevens op het account (in bytes). Dit saldo wordt "rent" genoemd, maar het werkt meer als een borg omdat je het volledige bedrag kunt terugkrijgen wanneer je een account sluit. Je kunt de berekening hier vinden met deze constanten.
De term "rent" komt van een verouderd mechanisme dat regelmatig lamports aftrok van accounts die onder de rent-drempel vielen. Dit mechanisme is niet langer actief.
Programma-eigenaar
Op Solana worden "smart contracts" programma's genoemd. Programma- eigendom is een essentieel onderdeel van het Solana Account Model. Elk account heeft een aangewezen programma als eigenaar. Alleen het eigenaarsprogramma kan:
- Het
data
veld van het account wijzigen - Lamports aftrekken van het saldo van het account
Elk programma definieert de structuur van de gegevens die zijn opgeslagen in het
data
veld van een account. De instructies van het programma bepalen hoe deze
gegevens en het lamports
saldo van het account kunnen worden gewijzigd.
System Program
Standaard zijn alle nieuwe accounts eigendom van het System Program. Het System Program voert de volgende belangrijke functies uit:
Functie | Beschrijving |
---|---|
Aanmaken van nieuwe accounts | Alleen het System Program kan nieuwe accounts aanmaken. |
Ruimtetoewijzing | Stelt de bytecapaciteit in voor het gegevensveld van elk account. |
Toewijzen van programma-eigendom | Zodra het System Program een account heeft aangemaakt, kan het de aangewezen programma-eigenaar opnieuw toewijzen aan een ander program account. Zo nemen aangepaste programma's eigendom over van nieuwe accounts die door het System Program zijn aangemaakt. |
SOL overmaken | Maakt lamports (SOL) over van System Accounts naar andere accounts. |
Merk op dat alle "wallet" accounts op Solana "System Accounts" zijn die eigendom zijn van het System Program. Het lamport saldo in deze accounts toont de hoeveelheid SOL die de wallet bezit. Alleen System Accounts kunnen transactiekosten betalen.
System Account
Wanneer SOL voor het eerst naar een nieuw adres wordt verzonden, wordt er automatisch een account aangemaakt op dat adres dat eigendom is van het System Program.
In het onderstaande voorbeeld wordt een nieuw keypair gegenereerd en
gefinancierd met SOL. Voer de code uit om de uitvoer te zien. Merk op dat het
veld owner
van het account het System Program is met het adres
11111111111111111111111111111111
.
import {airdropFactory,createSolanaRpc,createSolanaRpcSubscriptions,generateKeyPairSigner,lamports} from "@solana/kit";// Create a connection to Solana clusterconst rpc = createSolanaRpc("http://localhost:8899");const rpcSubscriptions = createSolanaRpcSubscriptions("ws://localhost:8900");// Generate a new keypairconst keypair = await generateKeyPairSigner();console.log(`Public Key: ${keypair.address}`);// Funding an address with SOL automatically creates an accountconst signature = await airdropFactory({ rpc, rpcSubscriptions })({recipientAddress: keypair.address,lamports: lamports(1_000_000_000n),commitment: "confirmed"});const accountInfo = await rpc.getAccountInfo(keypair.address).send();console.log(accountInfo);
Sysvar accounts
Sysvar accounts zijn speciale accounts op vooraf gedefinieerde adressen die toegang bieden tot cluster statusgegevens. Deze accounts worden dynamisch bijgewerkt met gegevens over het netwerkcluster. Je kunt de volledige lijst van Sysvar Accounts hier vinden.
Het volgende voorbeeld laat zien hoe je de gegevens van het Sysvar Clock account kunt ophalen en deserialiseren.
import { createSolanaRpc } from "@solana/kit";import { fetchSysvarClock, SYSVAR_CLOCK_ADDRESS } from "@solana/sysvars";const rpc = createSolanaRpc("https://api.mainnet-beta.solana.com");const accountInfo = await rpc.getAccountInfo(SYSVAR_CLOCK_ADDRESS, { encoding: "base64" }).send();console.log(accountInfo);// Automatically fetch and deserialize the account dataconst clock = await fetchSysvarClock(rpc);console.log(clock);
Program account
Het implementeren van een Solana-programma creëert een uitvoerbaar program account. Het program account slaat de uitvoerbare code van het programma op. Program accounts zijn eigendom van een Loader Program.
Program Account
Voor de eenvoud kun je het program account behandelen als het programma zelf. Wanneer je de instructies van een programma aanroept, specificeer je het adres van het program account (algemeen bekend als de "Program ID").
Het volgende voorbeeld haalt het Token Program account op om te laten zien dat
program accounts hetzelfde basis Account
type hebben, behalve dat het veld
executable
is ingesteld op true
. Omdat program accounts uitvoerbare code in
hun gegevensveld bevatten, deserialiseren we de gegevens niet.
import { Address, createSolanaRpc } from "@solana/kit";const rpc = createSolanaRpc("https://api.mainnet-beta.solana.com");const programId = "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" as Address;const accountInfo = await rpc.getAccountInfo(programId, { encoding: "base64" }).send();console.log(accountInfo);
Wanneer je een Solana-programma implementeert, wordt het opgeslagen in een program account. Program accounts zijn eigendom van een Loader-programma. Er zijn verschillende versies van de loader, maar alle behalve loader-v3 slaan de uitvoerbare code direct op in het program account. Loader-v3 slaat de uitvoerbare code op in een apart "program data account" en het program account verwijst er alleen naar. Wanneer je een nieuw programma implementeert, gebruikt de Solana CLI standaard de nieuwste loader-versie.
Buffer-account
Loader-v3 heeft een speciaal accounttype voor het tijdelijk opslaan van een programma tijdens implementatie of upgrades. In loader-v4 zijn er nog steeds buffers, maar dit zijn gewoon normale program accounts.
Program data account
Loader-v3 werkt anders dan alle andere BPF Loader-programma's. Het program account bevat alleen het adres van een program data account, dat de daadwerkelijke uitvoerbare code opslaat:
Program Data Account
Verwar deze program data accounts niet met de data accounts van programma's (zie hieronder).
Data-account
Op Solana wordt de uitvoerbare code van een programma opgeslagen in een ander account dan de status van het programma. Dit is vergelijkbaar met hoe besturingssystemen doorgaans aparte bestanden hebben voor programma's en hun gegevens.
Om de status bij te houden, definiëren programma's instructies om aparte accounts te maken die ze bezitten. Elk van deze accounts heeft zijn eigen unieke adres en kan willekeurige gegevens opslaan die door het programma zijn gedefinieerd.
Data Account
Merk op dat alleen het System Program nieuwe accounts kan aanmaken. Zodra het System Program een account heeft aangemaakt, kan het vervolgens het eigendom van het nieuwe account toewijzen aan een ander programma.
Met andere woorden, het creëren van een data-account voor een aangepast programma bestaat uit twee stappen:
- Roep het System Program aan om een account te maken en draag vervolgens het eigendom over aan het aangepaste programma
- Roep het aangepaste programma aan, dat nu eigenaar is van het account, om de accountgegevens te initialiseren zoals gedefinieerd door de instructie van het programma
Dit proces van accountcreatie wordt vaak geabstraheerd als een enkele stap, maar het is nuttig om het onderliggende proces te begrijpen.
Het volgende voorbeeld laat zien hoe je een Token Mint-account kunt maken en ophalen dat eigendom is van het Token 2022-programma.
import {airdropFactory,appendTransactionMessageInstructions,createSolanaRpc,createSolanaRpcSubscriptions,createTransactionMessage,generateKeyPairSigner,getSignatureFromTransaction,lamports,pipe,sendAndConfirmTransactionFactory,setTransactionMessageFeePayerSigner,setTransactionMessageLifetimeUsingBlockhash,signTransactionMessageWithSigners} from "@solana/kit";import { getCreateAccountInstruction } from "@solana-program/system";import {getInitializeMintInstruction,getMintSize,TOKEN_2022_PROGRAM_ADDRESS,fetchMint} from "@solana-program/token-2022";// Create Connection, local validator in this exampleconst rpc = createSolanaRpc("http://localhost:8899");const rpcSubscriptions = createSolanaRpcSubscriptions("ws://localhost:8900");// Generate keypairs for fee payerconst feePayer = await generateKeyPairSigner();// Fund fee payerawait airdropFactory({ rpc, rpcSubscriptions })({recipientAddress: feePayer.address,lamports: lamports(1_000_000_000n),commitment: "confirmed"});// Generate keypair to use as address of mintconst mint = await generateKeyPairSigner();// Get default mint account size (in bytes), no extensions enabledconst space = BigInt(getMintSize());// Get minimum balance for rent exemptionconst rent = await rpc.getMinimumBalanceForRentExemption(space).send();// Instruction to create new account for mint (token 2022 program)// Invokes the system programconst createAccountInstruction = getCreateAccountInstruction({payer: feePayer,newAccount: mint,lamports: rent,space,programAddress: TOKEN_2022_PROGRAM_ADDRESS});// Instruction to initialize mint account data// Invokes the token 2022 programconst initializeMintInstruction = getInitializeMintInstruction({mint: mint.address,decimals: 9,mintAuthority: feePayer.address});const instructions = [createAccountInstruction, initializeMintInstruction];// Get latest blockhash to include in transactionconst { value: latestBlockhash } = await rpc.getLatestBlockhash().send();// Create transaction messageconst transactionMessage = pipe(createTransactionMessage({ version: 0 }), // Create transaction message(tx) => setTransactionMessageFeePayerSigner(feePayer, tx), // Set fee payer(tx) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx), // Set transaction blockhash(tx) => appendTransactionMessageInstructions(instructions, tx) // Append instructions);// Sign transaction message with required signers (fee payer and mint keypair)const signedTransaction =await signTransactionMessageWithSigners(transactionMessage);// Send and confirm transactionawait sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })(signedTransaction,{ commitment: "confirmed" });// Get transaction signatureconst transactionSignature = getSignatureFromTransaction(signedTransaction);console.log("Mint Address:", mint.address);console.log("Transaction Signature:", transactionSignature);const accountInfo = await rpc.getAccountInfo(mint.address).send();console.log(accountInfo);const mintAccount = await fetchMint(rpc, mint.address);console.log(mintAccount);
Is this page helpful?