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 loyer 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 comptes de programme 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, où l'adresse est la clé permettant de localiser les données correspondantes on-chain du compte. 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 leur 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 Account de base.
Type de compte
Chaque compte sur Solana possède les champs suivants :
data
: Un tableau d'octets qui stocke des données arbitraires pour un compte. Pour les comptes non exécutables, cela stocke souvent l'état destiné à être lu. Pour les comptes de programme (contrats intelligents), cela contient le code de programme exécutable. Le champ de données est communément appelé "données de compte".executable
: Ce drapeau indique si un compte est un programme.lamports
: Le solde du compte en lamports, la plus petite unité de SOL (1 SOL = 1 milliard de lamports).owner
: L'ID du programme (clé publique) du programme qui possède ce compte. Seul le programme propriétaire peut modifier les données du compte ou déduire son solde en lamports.rent_epoch
: Un champ hérité de l'époque où Solana disposait d'un mécanisme qui déduisait périodiquement des lamports des comptes. Bien que ce champ existe toujours dans le type Account, il n'est plus utilisé depuis que la collecte de loyer a été dépréciée.
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);
Loyer
Pour stocker des données sur la chaîne, les comptes doivent également maintenir un solde en lamports (SOL) qui est proportionnel à la quantité de données stockées sur le compte (en octets). Ce solde est appelé "loyer", 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 "loyer" provient d'un mécanisme obsolète qui déduisait régulièrement des lamports des comptes qui tombaient en dessous du seuil de loyer. Ce mécanisme n'est plus actif aujourd'hui.
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
Programme système
Par défaut, tous les nouveaux comptes appartiennent au Programme système. Le Programme système effectue quelques fonctions clés :
- Création de nouveaux comptes : Seul le Programme système peut créer de nouveaux comptes.
- Allocation d'espace : Définit la capacité en octets pour le champ de données de chaque compte.
- Transfert / Attribution de propriété de programme : Une fois que le Programme système crée un compte, il peut réattribuer le propriétaire du programme désigné à un compte de programme différent. C'est ainsi que les programmes personnalisés prennent possession des nouveaux comptes créés par le Programme système.
Tous les comptes de "portefeuille" sur Solana sont simplement des comptes appartenant au Programme système. Le solde en lamports dans ces comptes indique la quantité de SOL détenue par le portefeuille. Seuls les comptes appartenant au Programme système peuvent payer les frais de transaction.
Compte système
Comptes Sysvar
Les comptes Sysvar sont des comptes spéciaux à des adresses prédéfinies qui fournissent un accès aux données d'état du cluster. Ces comptes se mettent à jour dynamiquement avec les données concernant le cluster réseau. Vous pouvez trouver la liste complète des comptes Sysvar ici.
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);
Compte de programme
Le déploiement d'un programme Solana crée un compte de programme exécutable. Le compte de programme stocke le code exécutable du programme.
Les comptes de programme sont détenus par un Programme chargeur.
Compte de programme
Pour simplifier, vous pouvez considérer le compte de programme comme le programme lui-même. Lorsque vous invoquez les instructions d'un programme, vous spécifiez l'adresse du compte de programme (communément appelée "ID de 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);
Lorsque vous déployez un programme Solana, il est stocké dans un compte de programme. Les comptes de programme 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 compte de programme. Loader-v3 stocke le code exécutable dans un "compte de données de programme" séparé et le compte de programme 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 le stockage temporaire lors du téléchargement d'un programme pendant le déploiement ou le redéploiement/mises à niveau. Dans loader-v4, il existe encore des tampons, mais ce sont simplement des comptes de programme normaux.
Compte de données de programme
Loader-v3 fonctionne différemment de tous les autres programmes BPF Loader. Le compte de programme 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 celui 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 quelles données arbitraires définies par le programme.
Compte de données
Notez que seul le Programme Système peut créer de nouveaux comptes. Une fois que le Programme Système crée un compte, il peut ensuite transférer ou 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 Programme Système 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 abstrait en une seule étape, mais il est utile de comprendre le processus sous-jacent.
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?