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.

ComptesComptes

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 compteAdresse 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 keys
const keypairSigner = await generateKeyPairSigner();
console.log(keypairSigner);
Console
Click to execute the code.

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}`);
Console
Click to execute the code.

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 compteType de compte

Chaque compte sur Solana possède les champs suivants.

Base Account Type
pub struct Account {
/// lamports in the account
pub 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 rent
pub 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 :

  1. Récupérer le compte en utilisant son adresse (clé publique)
  2. 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é.

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 :

  1. Récupérer le compte en utilisant son adresse (clé publique)
  2. 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é.

Base Account Type
pub struct Account {
/// lamports in the account
pub lamports: u64,
}
// Example Token Mint Account
Account {
lamports: 1461600,
}
// Example Token Program Account
Account {
lamports: 4513200894,
}

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 :

FonctionDescription
Création de nouveaux comptesSeul le System Program peut créer de nouveaux comptes.
Allocation d'espaceDéfinit la capacité en octets pour le champ de données de chaque compte.
Attribution de propriété de programmeUne 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 SOLTransfè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èmeCompte 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 cluster
const rpc = createSolanaRpc("http://localhost:8899");
const rpcSubscriptions = createSolanaRpcSubscriptions("ws://localhost:8900");
// Generate a new keypair
const keypair = await generateKeyPairSigner();
console.log(`Public Key: ${keypair.address}`);
// Funding an address with SOL automatically creates an account
const 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);
Console
Click to execute the code.

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 data
const clock = await fetchSysvarClock(rpc);
console.log(clock);
Console
Click to execute the code.

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 AccountProgram 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);
Console
Click to execute the code.

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 programmeCompte 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éesCompte 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 :

  1. Invoquer le System Program pour créer un compte, puis transférer la propriété au programme personnalisé
  2. 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 example
const rpc = createSolanaRpc("http://localhost:8899");
const rpcSubscriptions = createSolanaRpcSubscriptions("ws://localhost:8900");
// Generate keypairs for fee payer
const feePayer = await generateKeyPairSigner();
// Fund fee payer
await airdropFactory({ rpc, rpcSubscriptions })({
recipientAddress: feePayer.address,
lamports: lamports(1_000_000_000n),
commitment: "confirmed"
});
// Generate keypair to use as address of mint
const mint = await generateKeyPairSigner();
// Get default mint account size (in bytes), no extensions enabled
const space = BigInt(getMintSize());
// Get minimum balance for rent exemption
const rent = await rpc.getMinimumBalanceForRentExemption(space).send();
// Instruction to create new account for mint (token 2022 program)
// Invokes the system program
const createAccountInstruction = getCreateAccountInstruction({
payer: feePayer,
newAccount: mint,
lamports: rent,
space,
programAddress: TOKEN_2022_PROGRAM_ADDRESS
});
// Instruction to initialize mint account data
// Invokes the token 2022 program
const initializeMintInstruction = getInitializeMintInstruction({
mint: mint.address,
decimals: 9,
mintAuthority: feePayer.address
});
const instructions = [createAccountInstruction, initializeMintInstruction];
// Get latest blockhash to include in transaction
const { value: latestBlockhash } = await rpc.getLatestBlockhash().send();
// Create transaction message
const 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 transaction
await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })(
signedTransaction,
{ commitment: "confirmed" }
);
// Get transaction signature
const 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);
Console
Click to execute the code.

Is this page helpful?

Table des matières

Modifier la page