Modello di Account Solana
Su Solana, tutti i dati sono memorizzati in quelli che vengono chiamati "account". Puoi pensare ai dati su Solana come a un database pubblico con una singola tabella "Account", dove ogni voce in questa tabella è un "account". Ogni account Solana condivide lo stesso tipo di Account di base.
Account
Punti chiave
- Gli account possono memorizzare fino a 10MiB di dati, che contengono codice di programma eseguibile o stato del programma.
- Gli account richiedono un deposito di rent in lamport (SOL) proporzionale alla quantità di dati memorizzati, e puoi recuperarlo completamente quando chiudi l'account.
- Ogni account ha un proprietario di programma. Solo il programma che possiede un account può modificare i suoi dati o detrarre il suo saldo in lamport. Ma chiunque può aumentare il saldo.
- Account sysvar sono account speciali che memorizzano lo stato del cluster di rete.
- Program account memorizzano il codice eseguibile degli smart contract.
- Account dati sono creati dai programmi per memorizzare e gestire lo stato del programma.
Account
Ogni account su Solana ha un indirizzo univoco di 32 byte, spesso mostrato come
una stringa codificata in base58 (es.
14grJpemFaf88c8tiVb77W7TYg2W3ir6pfkKz3YjhhZ5
).
La relazione tra l'account e il suo indirizzo funziona come una coppia chiave-valore, dove l'indirizzo è la chiave per localizzare i dati on-chain corrispondenti dell'account. L'indirizzo dell'account funge da "ID univoco" per ogni voce nella tabella "Account".
Indirizzo Account
La maggior parte degli account Solana utilizza una chiave pubblica Ed25519 come indirizzo.
import { generateKeyPairSigner } from "@solana/kit";// Kit does not enable extractable private keysconst keypairSigner = await generateKeyPairSigner();console.log(keypairSigner);
Mentre le chiavi pubbliche sono comunemente utilizzate come indirizzi degli account, Solana supporta anche una funzionalità chiamata Program Derived Addresses (PDA). I PDA sono indirizzi speciali che puoi derivare deterministicamente da un ID di programma e input opzionali (seed).
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}`);
Tipo di account
Gli account hanno una dimensione massima di 10MiB e ogni account su Solana condivide lo stesso Account di base.
Tipo di Account
Ogni account su Solana ha i seguenti campi.
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,}
Campo Lamports
Il saldo dell'account in lamport, l'unità più piccola di SOL (1 SOL = 1 miliardo
di lamport). Il saldo SOL di un account è l'importo nel campo lamports
convertito in SOL.
Gli account Solana devono avere un saldo minimo di lamport proporzionale alla quantità di dati memorizzati sull'account (in byte). Questo saldo minimo è chiamato "rent".
Il saldo in lamport memorizzato nell'account può essere completamente recuperato quando l'account viene chiuso.
Campo Data
Un array di byte che memorizza dati arbitrari per un account. Il campo data è comunemente chiamato "dati dell'account".
- Per i program account (smart contract), questo campo contiene il codice del programma eseguibile stesso o l'indirizzo di un altro account che memorizza il codice del programma eseguibile.
- Per gli account non eseguibili, questo generalmente memorizza lo stato che deve essere letto.
La lettura dei dati da un account Solana comporta due passaggi:
- Recuperare l'account utilizzando il suo indirizzo (chiave pubblica)
- Deserializzare il campo dati dell'account dai byte grezzi nella struttura dati appropriata, che è definita dal programma proprietario dell'account
Campo Owner
L'ID del programma (chiave pubblica) del programma che possiede questo account.
Ogni account Solana ha un programma designato come proprietario. Solo il programma che possiede un account può modificare i dati dell'account o detrarre il suo saldo in lamport.
Le istruzioni definite in un programma determinano come i dati dell'account e il saldo in lamport possono essere modificati.
Campo Executable
Questo campo indica se un account è un programma eseguibile.
- Se
true
, l'account è un programma Solana eseguibile. - Se
false
, l'account è un account di dati che memorizza lo stato.
Per gli account eseguibili, il campo owner
contiene l'ID del programma di un
programma loader. I programmi loader sono programmi integrati responsabili del
caricamento e della gestione degli account di programma eseguibili.
Campo Rent Epoch
Il campo rent_epoch
è un campo legacy che non viene più utilizzato.
Originariamente, questo campo teneva traccia di quando un account avrebbe dovuto pagare il rent (in lamport) per mantenere i suoi dati sulla rete. Tuttavia, questo meccanismo di riscossione del rent è stato successivamente deprecato.
Rent
Per memorizzare dati on-chain, gli account devono anche mantenere un saldo in lamport (SOL) che sia proporzionale alla quantità di dati memorizzati sull'account (in byte). Questo saldo è chiamato "rent", ma funziona più come un deposito perché è possibile recuperare l'intero importo quando si chiude un account. Puoi trovare il calcolo qui utilizzando queste costanti.
Il termine "rent" deriva da un meccanismo deprecato che detraeva regolarmente lamport dagli account che scendevano sotto la soglia del rent. Questo meccanismo non è più attivo.
Program Owner
Su Solana, gli "smart contract" sono chiamati programmi. La proprietà del programma è una parte fondamentale del Modello di Account di Solana. Ogni account ha un programma designato come proprietario. Solo il programma proprietario può:
- Modificare il campo
data
dell'account - Detrarre lamport dal saldo dell'account
Ogni programma definisce la struttura dei dati memorizzati nel campo data
di
un account. Le istruzioni del programma determinano come questi dati e il saldo
lamports
dell'account possono essere modificati.
System Program
Per impostazione predefinita, tutti i nuovi account appartengono al System Program. Il System Program svolge le seguenti funzioni chiave:
Funzione | Descrizione |
---|---|
Creazione di nuovi account | Solo il System Program può creare nuovi account. |
Allocazione dello spazio | Imposta la capacità in byte per il campo dati di ciascun account. |
Assegnazione della proprietà del programma | Una volta che il System Program crea un account, può riassegnare il proprietario designato del programma a un account di programma diverso. È così che i programmi personalizzati prendono possesso dei nuovi account creati dal System Program. |
Trasferimento di SOL | Trasferisce lamport (SOL) dagli account di sistema ad altri account. |
Nota che tutti gli account "wallet" su Solana sono "System Account" di proprietà del System Program. Il saldo in lamport in questi account mostra la quantità di SOL posseduta dal wallet. Solo gli account di sistema possono pagare le commissioni di transazione.
Account di sistema
Quando SOL viene inviato a un nuovo indirizzo per la prima volta, viene automaticamente creato un account a quell'indirizzo di proprietà del System Program.
Nell'esempio seguente, viene generato un nuovo keypair e finanziato con SOL.
Esegui il codice per vedere l'output. Nota che il campo owner
dell'account è
il System Program con l'indirizzo 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);
Account Sysvar
Gli account Sysvar sono account speciali con indirizzi predefiniti che forniscono accesso ai dati sullo stato del cluster. Questi account si aggiornano dinamicamente con dati sul cluster di rete. Puoi trovare l'elenco completo degli Account Sysvar qui.
L'esempio seguente mostra come recuperare e deserializzare i dati dall'account Sysvar Clock.
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
Il deployment di un programma Solana crea un account di programma eseguibile. Il program account memorizza il codice eseguibile del programma. Gli account di programma sono di proprietà di un Loader Program.
Program Account
Per semplicità, puoi considerare il program account come il programma stesso. Quando invochi le istruzioni di un programma, specifichi l'indirizzo dell'account del programma (comunemente chiamato "Program ID").
L'esempio seguente recupera l'account del Token Program per mostrare che gli
account di programma hanno lo stesso tipo base Account
, eccetto che il campo
executable
è impostato su true
. Poiché gli account di programma contengono
codice eseguibile nel loro campo dati, non deseriallizziamo i dati.
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);
Quando fai il deployment di un programma Solana, viene memorizzato in un program account. I program account sono di proprietà di un Loader Program. Esistono diverse versioni del loader, ma tutte tranne loader-v3 memorizzano il codice eseguibile direttamente nell'account del programma. Loader-v3 memorizza il codice eseguibile in un "program data account" separato e l'account del programma si limita a puntare ad esso. Quando fai il deployment di un nuovo programma, la CLI di Solana utilizza l'ultima versione del loader per impostazione predefinita.
Account Buffer
Loader-v3 ha un tipo di account speciale per la preparazione temporanea del caricamento di un programma durante la distribuzione o gli aggiornamenti. In loader-v4, ci sono ancora buffer, ma sono semplicemente normali program account.
Program Data Account
Loader-v3 funziona diversamente da tutti gli altri programmi BPF Loader. Il program account contiene solo l'indirizzo di un program data account, che memorizza il codice eseguibile effettivo:
Program Data Account
Non confondere questi program data account con i data account dei programmi (vedi sotto).
Data Account
Su Solana, il codice eseguibile di un programma è memorizzato in un account diverso rispetto allo stato del programma. Questo è simile a come i sistemi operativi tipicamente hanno file separati per i programmi e i loro dati.
Per mantenere lo stato, i programmi definiscono istruzioni per creare account separati che possiedono. Ciascuno di questi account ha il proprio indirizzo univoco e può memorizzare qualsiasi dato arbitrario definito dal programma.
Data Account
Nota che solo il System Program può creare nuovi account. Una volta che il System Program crea un account, può quindi assegnare la proprietà del nuovo account a un altro programma.
In altre parole, la creazione di un data account per un programma personalizzato richiede due passaggi:
- Invocare il System Program per creare un account, quindi trasferire la proprietà al programma personalizzato
- Invocare il programma personalizzato, che ora possiede l'account, per inizializzare i dati dell'account come definito dall'istruzione del programma
Questo processo di creazione dell'account è spesso astratto come un singolo passaggio, ma è utile comprendere il processo sottostante.
Il seguente esempio mostra come creare e recuperare un account Token Mint posseduto dal programma Token 2022.
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?