Comptes
Toutes les données sur le réseau Solana sont stockées dans des comptes. Vous pouvez considérer le réseau Solana comme une base de données publique avec une seule table de Comptes. La relation entre un compte et son adresse est similaire à celle d'une paire clé-valeur (key-value), la clé étant l'adresse et la valeur étant le compte.
Chaque compte a la même structure de base et peut être localisé en utilisant son adresse.
Diagramme de 3 comptes et leurs adresses. Inclut la définition de la structure du compte.
Adresse du compte
L'adresse du compte est un identifiant unique de 32 octets utilisé pour localiser le compte sur la blockchain Solana. Les adresses de compte sont souvent affichées sous forme de chaînes encodées en base58. La plupart des comptes utilisent une clé publique Ed25519 comme adresse, mais ce n'est pas obligatoire, car Solana prend également en charge les adresses dérivées de programme.
Un compte avec son adresse de clé publique encodée en base58
Clé publique
L'exemple ci-dessous montre comment utiliser le SDK Solana pour créer un
keypair. Un Keypair comprend :
- Une clé publique qui sert d'adresse du compte
- Une clé privée qui est utilisée pour signer les transactions
import { generateKeyPairSigner } from "@solana/kit";// Kit does not enable extractable private keysconst keypairSigner = await generateKeyPairSigner();console.log(keypairSigner);
Program Derived Address
Une Program Derived Address (PDA) est une adresse qui est déterminée de manière déterministe en utilisant un ID de programme et une ou plusieurs entrées optionnelles (seeds). L'exemple ci-dessous montre comment utiliser le SDK Solana pour créer une Program Derived Address.
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}`);
Structure du compte
Chaque
Account
a une taille maximale de
10MiB
et contient les informations suivantes :
lamports: Le nombre de lamports dans le comptedata: Les données du compteowner: L'ID du programme qui possède le compteexecutable: Indique si le compte contient un binaire exécutablerent_epoch: Le champ d'epoch de rent déprécié
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
Le solde du compte en lamports.
Chaque compte doit avoir un solde minimum en lamports, appelé rent, qui permet de stocker ses données sur la chaîne. Le rent est proportionnel à la taille du compte.
Bien que ce solde soit appelé rent, il fonctionne davantage comme un dépôt, car le solde complet peut être récupéré lorsque le compte est fermé. (Le nom "rent" provient du champ d'epoch de rent désormais obsolète.)
(Voir la formule de solde minimum et les constantes applicables.)
Données
Ce champ est communément appelé "données du compte". Les data dans ce champ
sont considérées comme arbitraires car elles peuvent contenir n'importe quelle
séquence d'octets. Chaque programme définit la structure des données stockées
dans ce champ.
- Program accounts : ce champ contient soit du code de programme exécutable, soit l'adresse d'un compte de données de programme qui stocke le code de programme exécutable.
- Comptes de données : ce champ stocke généralement des données d'état, destinées à être lues.
La lecture des données d'un compte Solana implique deux étapes :
- Récupérer le compte en utilisant son adresse
- Désérialiser le champ
datadu compte à partir d'octets bruts vers la structure de données appropriée, telle que définie par le programme propriétaire du compte.
Propriétaire
Ce champ contient l'identifiant du programme propriétaire du compte.
Chaque compte Solana a un programme désigné comme son
propriétaire. Le propriétaire du compte est le seul programme qui peut modifier
les data du compte ou déduire des lamports, selon les instructions du
programme.
(Dans le cas d'un program account, le propriétaire est son programme chargeur.)
Exécutable
Ce champ indique si un compte est un program account ou un compte de données
- Si
true: le compte est un program account - Si
false: le compte est un compte de données
Epoch de rent
Le champ rent_epoch est obsolète.
Par le passé, ce champ suivait quand un compte devait payer le rent. Cependant, ce mécanisme de collecte de rent a depuis été abandonné.
Types de comptes
Il existe deux catégories principales de comptes :
- Comptes de programme : Comptes qui contiennent du code exécutable
- Comptes de données : Comptes qui ne contiennent pas de code exécutable
Cette séparation entre le code d'un programme et son état est une caractéristique clé du modèle de compte de Solana. (Similaire aux systèmes d'exploitation, qui ont généralement des fichiers séparés pour les programmes et leurs données.)
Comptes de programme
Chaque programme appartient à un programme chargeur, qui est utilisé pour déployer et gérer le compte. Lorsqu'un nouveau programme est déployé, un compte est créé pour stocker son code exécutable. C'est ce qu'on appelle un program account. (Par souci de simplicité, vous pouvez considérer le program account comme étant le programme lui-même.)
Dans le diagramme ci-dessous, vous pouvez voir qu'un programme chargeur est
utilisé pour déployer un program account. Le champ data du program account
contient le code exécutable du programme.
Diagramme d'un compte de programme, ses 4 composants et son programme chargeur.
Comptes de données de programme
Les programmes déployés à l'aide de loader-v3 ne contiennent pas de code de
programme dans leur champ data. Au lieu de cela, leur data pointe vers un
compte de données de programme séparé, qui contient le code du programme.
(Voir le diagramme ci-dessous.)
Un compte de programme avec des données. Les données pointent vers un compte de données de programme séparé
Pendant le déploiement ou les mises à niveau du programme, des comptes tampons sont utilisés pour préparer temporairement le téléchargement.
L'exemple ci-dessous récupère le compte du Token Program. Notez que le champ
executable est défini sur true, indiquant que le compte est un programme.
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);
Comptes de données
Les comptes de données ne contiennent pas de code exécutable. Au lieu de cela, ils stockent des informations.
Compte d'état du programme
Les programmes utilisent des comptes de données pour maintenir leur état. Pour ce faire, ils doivent d'abord créer un nouveau compte de données. Le processus de création d'un compte d'état de programme est souvent abstrait, mais il est utile de comprendre le processus sous-jacent.
Pour gérer son état, un nouveau programme doit :
- Invoquer le System Program pour créer un compte. (Le System Program transfère ensuite la propriété au nouveau programme.)
- Initialiser les données du compte, comme défini par ses instructions.
Diagramme d'un compte de données appartenant à un compte de programme
L'exemple ci-dessous crée et récupère un compte Token Mint appartenant au programme 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);
Comptes système
Tous les comptes ne se voient pas attribuer un nouveau propriétaire après avoir été créés par le System Program. Les comptes appartenant au System Program sont appelés comptes système. Tous les comptes de portefeuille sont des comptes système, ce qui leur permet de payer des frais de transaction.
Un portefeuille appartenant au System Program contenant 1 000 000 lamports
Lorsque du SOL est envoyé à une nouvelle adresse pour la première fois, un compte est créé à cette adresse, appartenant au System Program.
Dans l'exemple ci-dessous, une nouvelle paire de clés est générée et financée
avec du SOL. Après avoir exécuté le code, vous pouvez voir que l'adresse du
owner du compte est 11111111111111111111111111111111 (le
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);
Comptes Sysvar
Les comptes Sysvar existent à des adresses prédéfinies et fournissent un accès aux données d'état du cluster. Ils se mettent à jour dynamiquement avec les données concernant le réseau du cluster. Consultez la liste complète des Comptes Sysvar.
L'exemple ci-dessous récupère et désérialise les données du compte 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);
Is this page helpful?