Exécution des comptes

Résumé

Avant l'exécution, le runtime charge les comptes, valide le payeur de frais, vérifie l'exemption de loyer et sérialise les données de compte dans une disposition mémoire accessible aux programmes.

Cette page couvre les mécanismes internes du runtime. La plupart des développeurs n'ont pas besoin de ces informations pour créer des programmes. Consultez Structure des comptes pour la vue destinée aux développeurs.

Chargement des comptes

Avant l'exécution d'une transaction, le runtime charge tous les comptes référencés via load_transaction_accounts(). Ce processus effectue plusieurs validations :

  1. Validation du payeur de frais : le payeur de frais (premier compte) doit exister, être un compte système ou un compte nonce, et disposer de suffisamment de lamports pour couvrir les frais (validate_fee_payer()). Après paiement des frais, le compte doit soit rester exempté de loyer, soit atteindre exactement 0 lamport. Il ne peut pas se retrouver entre 0 et le minimum d'exemption de loyer. Les comptes nonce doivent toujours conserver suffisamment de lamports pour rester exemptés de loyer. Si le payeur n'est ni un compte système ni un compte nonce, la transaction échoue avec TransactionError::InvalidAccountForFee.

  2. Limite de taille des données chargées : la taille totale de tous les comptes chargés (incluant un TRANSACTION_ACCOUNT_BASE_SIZE de 64 octets par compte) ne doit pas dépasser MAX_LOADED_ACCOUNTS_DATA_SIZE_BYTES (64 Mio). Le dépassement de cette limite produit TransactionError::MaxLoadedAccountsDataSizeExceeded.

  3. Validation du compte de programme : chaque programme invoqué par une instruction doit exister et appartenir à un chargeur valide : l'un des PROGRAM_OWNERS (BPF Loader Upgradeable, BPF Loader, BPF Loader Deprecated, Loader V4) ou le chargeur natif. Si le compte de programme n'existe pas, la transaction échoue avec TransactionError::ProgramAccountNotFound. S'il existe mais possède un propriétaire invalide, la transaction échoue avec TransactionError::InvalidProgramForExecution.

  4. Comptes non existants : les comptes qui n'existent pas on-chain sont chargés en tant que comptes par défaut (0 lamport, données vides, détenus par le programme système) avec rent_epoch défini sur u64::MAX.

Format de sérialisation BPF

Lorsqu'un programme est invoqué, le runtime sérialise les comptes dans un tampon mémoire contigu et le transmet à la VM BPF. Le format de sérialisation (pour le format aligné standard utilisé par tous les chargeurs sauf le loader-v1 obsolète) est défini dans serialize_parameters_aligned().

Le tampon commence par un u64 (8 octets, little-endian) contenant le nombre de comptes. Ensuite, pour chaque compte dans l'instruction, le tampon contient :

DécalageTailleChampType
01marqueur de duplicationu8 (0xFF = unique, index = duplication de ce compte)
11is_signeru8 (0 ou 1)
21is_writableu8 (0 ou 1)
31executableu8 (0 ou 1)
44original_data_len (réservé, toujours 0)[0u8; 4]
832keyPubkey
4032ownerPubkey
728lamportsu64 (little-endian)
808data_lenu64 (little-endian)
88data_lendata[u8]
88 + data_len10240 + paddingespace de réallocation + alignementRempli de zéros jusqu'à MAX_PERMITTED_DATA_INCREASE (10 Kio) + padding pour aligner sur BPF_ALIGN_OF_U128 (8 octets)
...8rent_epochu64 (little-endian)

Après tous les comptes, le buffer ajoute :

TailleChamp
8instruction_data_len (u64, little-endian)
instruction_data_leninstruction_data
32program_id (Pubkey)

Pour les comptes dupliqués, seul 1 octet (le marqueur de duplication avec l'index de l'original) plus 7 octets de remplissage sont écrits.

Déduplication des comptes

Lorsque la même clé publique de compte apparaît plusieurs fois dans le tableau accounts d'une instruction, le runtime les déduplique. Chaque entrée dans la liste de comptes de l'instruction obtient sa propre structure InstructionAccount, mais les entrées qui font référence au même compte au niveau de la transaction pointent vers les mêmes données sous-jacentes.

La méthode is_instruction_account_duplicate détermine si un index de compte d'instruction donné est la première occurrence ou un duplicata en recherchant l'index de compte au niveau de la transaction et en trouvant le premier index au niveau de l'instruction qui y correspond :

  • Si l'index de compte d'instruction actuel est égal au premier index mappé, ce n'est pas un duplicata (retourne None).
  • Sinon, il retourne Some(first_index), où first_index est l'index de la première occurrence.

Étant donné que toutes les références au même compte partagent le même AccountSharedData sous-jacent, les modifications effectuées via n'importe quelle référence sont immédiatement visibles via toutes les autres références. Cependant, un seul emprunt mutable peut être détenu à la fois. Tenter d'emprunter le même compte de manière mutable via deux index de compte d'instruction différents simultanément retourne InstructionError::AccountBorrowFailed. Les programmes doivent libérer un emprunt avant d'en acquérir un autre sur le même compte sous-jacent.

Après l'exécution du programme, le runtime désérialise le buffer (deserialize_parameters_aligned()) et applique tous les changements à lamports, data (y compris les changements de longueur jusqu'à MAX_PERMITTED_DATA_INCREASE), et owner.

Is this page helpful?

Table des matières

Modifier la page

Géré par

© 2026 Fondation Solana.
Tous droits réservés.
Restez connecté