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.
vines1vzrYbzLMRdu58ou5XTby4qAqVRLmqo36NKPTg
).
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:
data
: Un array di byte che memorizza dati arbitrari per un account. Per account non eseguibili, spesso memorizza lo stato che deve essere letto. Per gli account di programma (smart contract), contiene il codice del programma eseguibile. Il campo dati è comunemente chiamato "dati dell'account".executable
: Questo flag indica se un account è un programma.lamports
: Il saldo dell'account in lamport, l'unità più piccola di SOL (1 SOL = 1 miliardo di lamport).owner
: L'ID del programma (chiave pubblica) del programma che possiede questo account. Solo il programma proprietario può modificare i dati dell'account o detrarre il suo saldo in lamport.rent_epoch
: Un campo legacy risalente a quando Solana aveva un meccanismo che detraeva periodicamente lamport dagli account. Sebbene questo campo esista ancora nel tipo Account, non viene più utilizzato da quando la riscossione del rent è stata deprecata.
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,}
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);
Rent
Per memorizzare dati on-chain, gli account devono anche mantenere un saldo in lamport (SOL) che è proporzionale alla quantità di dati memorizzati sull'account (in byte). Questo saldo è chiamato "rent", ma funziona più come un deposito perché puoi recuperare l'intero importo quando chiudi 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 di rent. Questo meccanismo non è più attivo.
Proprietario del programma
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
System Program
Per impostazione predefinita, tutti i nuovi account appartengono al System Program. Il System Program svolge alcune funzioni chiave:
- 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.
- Trasferimento / Assegnazione della proprietà del programma: Una volta che il System Program crea un account, può riassegnare il proprietario del programma designato a un account di programma diverso. È così che i programmi personalizzati prendono possesso dei nuovi account creati dal System Program.
Tutti gli account "wallet" su Solana sono semplicemente account posseduti dal System Program. Il saldo in lamport in questi account mostra la quantità di SOL posseduta dal wallet. Solo gli account posseduti dal System Program possono pagare le commissioni di transazione.
Account di sistema
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.
import { Address, createSolanaRpc } from "@solana/kit";const rpc = createSolanaRpc("https://api.mainnet-beta.solana.com");const SYSVAR_CLOCK_ADDRESS ="SysvarC1ock11111111111111111111111111111111" as Address;const accountInfo = await rpc.getAccountInfo(SYSVAR_CLOCK_ADDRESS, { encoding: "base64" }).send();console.log(accountInfo);
Program Account
Il deployment di un programma Solana crea un program account eseguibile. Il program account memorizza il codice eseguibile del programma.
I program account 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 del program account (comunemente chiamato "Program ID").
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 nel program account. Loader-v3 memorizza il codice eseguibile in un "program data account" separato e il program account 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.
Buffer Account
Loader-v3 ha un tipo di account speciale per la preparazione temporanea del caricamento di un programma durante il deployment o il redeployment/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:
Account di Dati del Programma
Non confondere questi account di dati del programma con gli account di dati dei programmi (vedi sotto).
Account di Dati
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 essi possiedono. Ciascuno di questi account ha il proprio indirizzo univoco e può memorizzare qualsiasi dato arbitrario definito dal programma.
Account di Dati
Nota che solo il System Program può creare nuovi account. Una volta che il System Program crea un account, può quindi trasferire o assegnare la proprietà del nuovo account a un altro programma.
In altre parole, creare un account di dati 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.
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} from "@solana-program/token-2022";// Create Connection, local validator in this exampleconst rpc = createSolanaRpc("http://127.0.0.1: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);
Is this page helpful?