Accounts
Alle gegevens op het Solana-netwerk worden opgeslagen in accounts. Je kunt het Solana-netwerk zien als een openbare database met één Accounts-tabel. De relatie tussen een account en zijn adres is vergelijkbaar met die van een sleutel-waardepaar, waarbij de sleutel het adres is en de waarde het account.
Elk account heeft dezelfde basis structuur en kan worden gelokaliseerd met behulp van zijn adres.
Diagram van 3 accounts en hun adressen. Bevat de definitie van de accountstructuur.
Account-adres
Het adres van het account is een unieke ID van 32 bytes die wordt gebruikt om het account op de Solana-blockchain te lokaliseren. Account-adressen worden vaak weergegeven als base58-gecodeerde strings. De meeste accounts gebruiken een Ed25519 publieke sleutel als hun adres, maar dit is niet vereist, aangezien Solana ook program derived addresses ondersteunt.
Een account met zijn base58-gecodeerde publieke sleuteladres
Publieke sleutel
Het onderstaande voorbeeld laat zien hoe je de Solana SDK kunt gebruiken om een keypair te maken.
import { generateKeyPairSigner } from "@solana/kit";// Kit does not enable extractable private keysconst keypairSigner = await generateKeyPairSigner();console.log(keypairSigner);
Console
Click to execute the code.
Program derived address
Een program derived address (PDA) is een adres dat deterministisch wordt afgeleid met behulp van een programma-ID en een of meer optionele inputs (seeds). Het onderstaande voorbeeld laat zien hoe je de Solana SDK kunt gebruiken om een program derived address te maken.
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}`);
Console
Click to execute the code.
Account-structuur
Elk
Account
heeft een maximale grootte van
10MiB
en bevat de volgende informatie:
lamports: Het aantal lamports in het accountdata: De gegevens van het accountowner: De ID van het programma dat eigenaar is van het accountexecutable: Geeft aan of het account een uitvoerbare binary bevatrent_epoch: Het verouderde rent epoch veld
Account
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
Het saldo van het account in lamports.
Elk account moet een minimaal lamport-saldo hebben, genaamd rent, waardoor de gegevens on-chain kunnen worden opgeslagen. Rent is evenredig aan de grootte van het account.
Hoewel dit saldo rent wordt genoemd, werkt het meer als een borg, aangezien het volledige saldo kan worden teruggevorderd wanneer het account wordt gesloten. (De naam "rent" komt van het nu verouderde rent epoch veld.)
(Zie de minimum saldo formule en de toepasselijke constanten.)
Data
Dit veld wordt vaak aangeduid als "account data". De data in dit veld wordt
beschouwd als willekeurig omdat het elke reeks bytes kan bevatten. Elk programma
defineert de structuur van de gegevens die in dit veld worden opgeslagen.
- Program accounts: Dit veld bevat ofwel uitvoerbare programmacode of het adres van een program data account dat de uitvoerbare programmacode opslaat.
- Data accounts: Dit veld slaat over het algemeen statusgegevens op, bedoeld om te lezen.
Het lezen van gegevens uit een Solana-account omvat twee stappen:
- Het ophalen van het account met behulp van het adres
- Het deserialiseren van het
dataveld van het account van ruwe bytes naar de juiste datastructuur, zoals gedefinieerd door het programma dat eigenaar is van het account.
Owner
Dit veld bevat de programma-ID van de eigenaar van het account.
Elk Solana-account heeft een programma aangewezen als
eigenaar. De eigenaar van het account is het enige programma dat de data van
het account kan wijzigen of lamports kan aftrekken, zoals aangegeven door de
instructies van het programma.
(In het geval van een program account is de eigenaar het loader-programma.
Uitvoerbaar
Dit veld geeft aan of een account een program account of een data account is
- Als
true: Het account is een program account - Als
false: Het account is een data account
Rent epoch
Het rent_epoch veld is verouderd.
In het verleden hield dit veld bij wanneer een account rent moest betalen. Dit rent-inzamelingsmechanisme is echter sindsdien verouderd verklaard.
Soorten accounts
Er zijn twee basiscategorieën waarin accounts vallen:
- Program accounts: Accounts die uitvoerbare code bevatten
- Data accounts: Accounts die geen uitvoerbare code bevatten
Deze scheiding betekent dat de uitvoerbare code van een programma en de status ervan in afzonderlijke accounts worden opgeslagen. (Vergelijkbaar met besturingssystemen, die doorgaans aparte bestanden hebben voor programma's en hun gegevens.)
Program accounts
Elk programma is eigendom van een loader-programma, dat wordt gebruikt om het account te implementeren en te beheren. Wanneer een nieuw programma wordt geïmplementeerd, wordt een account gemaakt om de uitvoerbare code op te slaan. Dit wordt een program account genoemd. (Voor de eenvoud kun je het program account beschouwen als het programma zelf.)
In het onderstaande diagram zie je dat een loader-programma wordt gebruikt om
een program account te implementeren. De data van het program account bevat de
uitvoerbare programmacode.
Diagram van een program account, de 4 componenten en het loader-programma.
Program data accounts
Programma's die zijn geïmplementeerd met loader-v3 bevatten geen programmacode
in hun data veld. In plaats daarvan verwijst hun data naar een apart
program data account, dat de programmacode bevat. (Zie het onderstaande
diagram.)
Een program account met gegevens. De gegevens verwijzen naar een apart program data account
Tijdens programma-implementatie of upgrades worden buffer-accounts gebruikt om de upload tijdelijk te bewaren.
Het onderstaande voorbeeld haalt het Token Program account op. Merk op dat het
executable veld is ingesteld op true, wat aangeeft dat het account een
programma is.
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);
Console
Click to execute the code.
Data-accounts
Data-accounts bevatten geen uitvoerbare code. In plaats daarvan slaan ze informatie op.
Program state account
Programma's gebruiken data-accounts om hun status bij te houden. Hiervoor moeten ze eerst een nieuw data-account aanmaken. Het proces van het aanmaken van een program state account wordt vaak geabstraheerd, maar het is nuttig om het onderliggende proces te begrijpen.
Om zijn status te beheren, moet een nieuw programma:
- Het System Program aanroepen om een account aan te maken. (Het System Program draagt vervolgens het eigendom over aan het nieuwe programma.)
- De accountgegevens initialiseren, zoals gedefinieerd door zijn instructies.
Diagram van een data-account dat eigendom is van een program account
Het onderstaande voorbeeld maakt een Token Mint account aan en haalt het op, 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);
Console
Click to execute the code.
System accounts
Niet alle accounts krijgen een nieuwe eigenaar nadat ze zijn aangemaakt door het System Program. Accounts die eigendom zijn van het System Program worden system accounts genoemd. Alle wallet-accounts zijn system accounts, waardoor ze transactiekosten kunnen betalen.
Een wallet eigendom van het System Program met 1.000.000 lamports
Wanneer SOL voor het eerst naar een nieuw adres wordt verzonden, wordt er een account aangemaakt op dat adres dat eigendom is van het System Program.
In het onderstaande voorbeeld wordt een nieuwe keypair gegenereerd en
gefinancierd met SOL. Na het uitvoeren van de code kun je zien dat het adres van
de owner van het account 11111111111111111111111111111111 is (het
System Program).
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);
Console
Click to execute the code.
Sysvar-accounts
Sysvar-accounts bestaan op vooraf gedefinieerde adressen en bieden toegang tot clusterstatusgegevens. Ze worden dynamisch bijgewerkt met gegevens over het netwerkcluster. Bekijk de volledige lijst van Sysvar-accounts.
Het onderstaande voorbeeld haalt gegevens op uit het Sysvar Clock-account en zet deze om.
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);
Console
Click to execute the code.
Is this page helpful?