Modèle de compte Solana
Sur Solana, toutes les données sont stockées dans ce qu'on appelle des "comptes". Vous pouvez considérer les données sur Solana comme une base de données publique avec une seule table "Comptes", où chaque entrée dans cette table est un "compte". Chaque compte Solana partage le même type de Compte de base.
Comptes
Points clés
- Les comptes peuvent stocker jusqu'à 10MiB de données, qui contiennent soit du code de programme exécutable, soit l'état du programme.
- Les comptes nécessitent un dépôt de rent en lamports (SOL) proportionnel à la quantité de données stockées, et vous pouvez le récupérer intégralement lorsque vous fermez le compte.
- Chaque compte a un propriétaire de programme. Seul le programme propriétaire d'un compte peut modifier ses données ou déduire son solde en lamports. Mais n'importe qui peut augmenter le solde.
- Les comptes Sysvar sont des comptes spéciaux qui stockent l'état du cluster réseau.
- Les program account stockent le code exécutable des contrats intelligents.
- Les comptes de données sont créés par des programmes pour stocker et gérer l'état du programme.
Compte
Chaque compte sur Solana possède une adresse unique de 32 octets, souvent
présentée sous forme de chaîne encodée en base58 (par exemple
14grJpemFaf88c8tiVb77W7TYg2W3ir6pfkKz3YjhhZ5
).
La relation entre le compte et son adresse fonctionne comme une paire clé-valeur (key-value), où l'adresse est la clé permettant de localiser les données correspondantes du compte sur la chaîne. L'adresse du compte agit comme "l'identifiant unique" pour chaque entrée dans la table "Comptes".
Adresse du compte
La plupart des comptes Solana utilisent une clé publique Ed25519 comme adresse.
import { generateKeyPairSigner } from "@solana/kit";// Kit does not enable extractable private keysconst keypairSigner = await generateKeyPairSigner();console.log(keypairSigner);
Bien que les clés publiques soient couramment utilisées comme adresses de compte, Solana prend également en charge une fonctionnalité appelée Adresses dérivées de programme (PDAs). Les PDAs sont des adresses spéciales que vous pouvez dériver de manière déterministe à partir d'un ID de programme et d'entrées optionnelles (seeds).
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}`);
Type de compte
Les comptes ont une taille maximale de 10MiB et chaque compte sur Solana partage le même type de compte de base.
Type de compte
Chaque compte sur Solana possède les champs suivants.
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,}
Champ Lamports
Le solde du compte en lamports, la plus petite unité de SOL (1 SOL = 1 milliard
de lamports). Le solde en SOL d'un compte est le montant dans le champ
lamports
converti en SOL.
Les comptes Solana doivent avoir un solde minimum en lamports qui est proportionnel à la quantité de données stockées sur le compte (en octets). Ce solde minimum est appelé "rent".
Le solde en lamports stocké dans le compte peut être entièrement récupéré lorsque le compte est fermé.
Champ de données
Un tableau d'octets qui stocke des données arbitraires pour un compte. Le champ de données est communément appelé "données du compte".
- Pour les program accounts (contrats intelligents), ce champ contient soit le code du programme exécutable lui-même, soit l'adresse d'un autre compte qui stocke le code du programme exécutable.
- Pour les comptes non exécutables, ce champ stocke généralement des états destinés à être lus.
La lecture des données d'un compte Solana implique deux étapes :
- Récupérer le compte en utilisant son adresse (clé publique)
- Désérialiser le champ de données du compte depuis les octets bruts vers la structure de données appropriée, qui est définie par le programme propriétaire du compte
Champ Propriétaire
L'ID du programme (clé publique) du programme qui possède ce compte.
Chaque compte Solana a un programme désigné comme son propriétaire. Seul le programme qui possède un compte peut modifier les données du compte ou déduire son solde en lamports.
Les instructions définies dans un programme déterminent comment les données du compte et le solde en lamports peuvent être modifiés.
Champ Executable
Ce champ indique si un compte est un programme exécutable.
- Si
true
, le compte est un programme Solana exécutable. - Si
false
, le compte est un compte de données qui stocke l'état.
Pour les comptes exécutables, le champ owner
contient l'identifiant du
programme chargeur. Les programmes chargeurs sont des programmes intégrés
responsables du chargement et de la gestion des comptes de programmes
exécutables.
Champ Rent Epoch
Le champ rent_epoch
est un champ hérité qui n'est plus utilisé.
À l'origine, ce champ suivait quand un compte devait payer du rent (en lamports) pour maintenir ses données sur le réseau. Cependant, ce mécanisme de collecte de rent a depuis été abandonné.
Rent
Pour stocker des données sur la chaîne, les comptes doivent également maintenir un solde en lamport (SOL) proportionnel à la quantité de données stockées sur le compte (en octets). Ce solde est appelé "rent", mais il fonctionne davantage comme un dépôt car vous pouvez récupérer le montant total lorsque vous fermez un compte. Vous pouvez trouver le calcul ici en utilisant ces constantes.
Le terme "rent" provient d'un mécanisme déprécié qui déduisait régulièrement des lamports des comptes qui tombaient en dessous du seuil de rent. Ce mécanisme n'est plus actif.
Propriétaire du programme
Sur Solana, les "smart contracts" sont appelés programmes. La propriété du programme est un élément clé du modèle de compte Solana. Chaque compte a un programme désigné comme propriétaire. Seul le programme propriétaire peut :
- Modifier le champ
data
du compte - Déduire des lamports du solde du compte
Chaque programme définit la structure des données stockées dans le champ data
d'un compte. Les instructions du programme déterminent comment ces données et le
solde lamports
du compte peuvent être modifiés.
System Program
Par défaut, tous les nouveaux comptes appartiennent au System Program. Le System Program remplit les fonctions clés suivantes :
Fonction | Description |
---|---|
Création de nouveaux comptes | Seul le System Program peut créer de nouveaux comptes. |
Allocation d'espace | Définit la capacité en octets pour le champ de données de chaque compte. |
Attribution de propriété de programme | Une fois que le System Program crée un compte, il peut réattribuer le propriétaire désigné du programme à un autre compte de programme. C'est ainsi que les programmes personnalisés prennent possession des nouveaux comptes créés par le System Program. |
Transfert de SOL | Transfère des lamports (SOL) des comptes système vers d'autres comptes. |
Notez que tous les comptes "portefeuille" sur Solana sont des "comptes système" appartenant au System Program. Le solde en lamports de ces comptes indique la quantité de SOL détenue par le portefeuille. Seuls les comptes système peuvent payer les frais de transaction.
Compte système
Lorsque du SOL est envoyé à une nouvelle adresse pour la première fois, un compte est automatiquement créé à cette adresse, appartenant au System Program.
Dans l'exemple ci-dessous, une nouvelle keypair est générée et financée avec du
SOL. Exécutez le code pour voir le résultat. Notez que le champ owner
du
compte est le System Program avec l'adresse 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);
Comptes Sysvar
Les comptes Sysvar sont des comptes spéciaux à des adresses prédéfinies qui donnent accès aux données d'état du cluster. Ces comptes se mettent à jour dynamiquement avec des données sur le cluster réseau. Vous pouvez trouver la liste complète des comptes Sysvar ici.
L'exemple suivant montre comment récupérer et désérialiser 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);
Program Account
Le déploiement d'un programme Solana crée un program account exécutable. Le program account stocke le code exécutable du programme. Les program accounts sont détenus par un Programme chargeur.
Program Account
Pour simplifier, vous pouvez considérer le program account comme le programme lui-même. Lorsque vous invoquez les instructions d'un programme, vous spécifiez l'adresse du program account (communément appelée "Program ID").
L'exemple suivant récupère le Token Program account pour montrer que les program
accounts ont le même type de base Account
, sauf que le champ executable
est
défini à true
. Comme les program accounts contiennent du code exécutable dans
leur champ de données, nous ne désérialisons pas les données.
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);
Lorsque vous déployez un programme Solana, il est stocké dans un program account. Les program accounts sont détenus par un Programme chargeur. Il existe plusieurs versions du chargeur, mais toutes sauf loader-v3 stockent le code exécutable directement dans le program account. Loader-v3 stocke le code exécutable dans un "program data account" séparé et le program account y fait simplement référence. Lorsque vous déployez un nouveau programme, le CLI Solana utilise la dernière version du chargeur par défaut.
Compte tampon
Loader-v3 possède un type de compte spécial pour organiser temporairement le téléchargement d'un programme pendant le déploiement ou les mises à niveau. Dans loader-v4, il y a toujours des tampons, mais ce sont simplement des program account normaux.
Compte de données de programme
Loader-v3 fonctionne différemment de tous les autres programmes BPF Loader. Le program account contient uniquement l'adresse d'un compte de données de programme, qui stocke le code exécutable réel :
Compte de données de programme
Ne confondez pas ces comptes de données de programme avec les comptes de données des programmes (voir ci-dessous).
Compte de données
Sur Solana, le code exécutable d'un programme est stocké dans un compte différent de l'état du programme. C'est similaire à la façon dont les systèmes d'exploitation ont généralement des fichiers séparés pour les programmes et leurs données.
Pour maintenir un état, les programmes définissent des instructions pour créer des comptes séparés qu'ils possèdent. Chacun de ces comptes a sa propre adresse unique et peut stocker n'importe quelle donnée arbitraire définie par le programme.
Compte de données
Notez que seul le System Program peut créer de nouveaux comptes. Une fois que le System Program crée un compte, il peut ensuite attribuer la propriété du nouveau compte à un autre programme.
En d'autres termes, la création d'un compte de données pour un programme personnalisé se fait en deux étapes :
- Invoquer le System Program pour créer un compte, puis transférer la propriété au programme personnalisé
- Invoquer le programme personnalisé, qui possède maintenant le compte, pour initialiser les données du compte comme défini par l'instruction du programme
Ce processus de création de compte est souvent présenté comme une seule étape, mais il est utile de comprendre le processus sous-jacent.
L'exemple suivant montre comment créer et récupérer un compte Token Mint détenu par le 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);
Is this page helpful?