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.
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éterministiquement dérivée 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 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 rent epoch maintenant 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.
- Comptes de programme : 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'ID 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 compte de programme, 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
Époque 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 :
- Program accounts : Comptes qui contiennent du code exécutable
- Comptes de données : Comptes qui ne contiennent pas de code exécutable
Cette séparation signifie que le code exécutable d'un programme et son état sont stockés dans des comptes séparés. (Similaire aux systèmes d'exploitation, qui ont généralement des fichiers séparés pour les programmes et leurs données.)
Program accounts
Chaque programme est détenu par 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. (Pour simplifier, 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 program account, 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 champ 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 de programmes, des comptes tampons sont utilisés pour organiser temporairement le téléchargement.
L'exemple ci-dessous récupère le compte du Token Program. Remarquez 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 sont pas assignés à 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 les 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, un nouveau keypair est généré et financé avec des
SOL. Après l'exécution du 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. 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?