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 del 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.
- Account programma 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.
vines1vzrYbzLMRdu58ou5XTby4qAqVRLmqo6X8TsVXREG
).
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 dell'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 del 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 tipo base Account.
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, questo spesso memorizza lo stato che deve essere letto. Per gli account di programma (smart contract), questo contiene il codice del programma eseguibile. Il campo data è 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 raccolta 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 a indirizzi predefiniti che forniscono accesso ai dati di 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);
Account di Programma
Il deployment di un programma Solana crea un account di programma eseguibile. L'account di programma memorizza il codice eseguibile del programma.
Gli account di programma sono di proprietà di un Loader Program.
Account di Programma
Per semplicità, puoi considerare l'account di programma come il programma stesso. Quando invochi le istruzioni di un programma, specifichi l'indirizzo dell'account di programma (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 account di programma. Gli account di programma sono di proprietà di un Loader Program. Esistono diverse versioni del loader, ma tutte tranne loader-v3 memorizzano il codice eseguibile direttamente nell'account di programma. Loader-v3 memorizza il codice eseguibile in un "account di dati del programma" separato e l'account di programma si limita a puntare ad esso. Quando fai il deployment di un nuovo programma, la CLI di Solana utilizza la versione più recente 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 il deployment o il redeployment/aggiornamenti. In loader-v4, ci sono ancora buffer, ma sono semplicemente normali account di programma.
Account di Dati del Programma
Loader-v3 funziona diversamente da tutti gli altri programmi BPF Loader. L'account di programma contiene solo l'indirizzo di un account di dati del programma, che memorizza il codice eseguibile effettivo:
Account dati del programma
Non confondere questi account dati del programma con gli account dati dei programmi (vedi sotto).
Account 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 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, la creazione di un account 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?