Résumé
Une instruction comporte 3 champs : program_id (quel programme invoquer),
accounts (liste AccountMeta avec indicateurs is_signer/is_writable), et
data (tableau d'octets de données que le programme interprète).
Structure des instructions
Une
Instruction
se compose de trois champs :
program_id: l'ID du programme invoqué.accounts: un tableau de métadonnées de comptedata: un tableau d'octets avec des données supplémentaires à utiliser par l'instruction.
pub struct Instruction {/// Pubkey of the program that executes this instruction.pub program_id: Pubkey,/// Metadata describing accounts that should be passed to the program.pub accounts: Vec<AccountMeta>,/// Opaque data passed to the program for its own interpretation.pub data: Vec<u8>,}
ID du programme
Le program_id de l'instruction est
l'adresse de clé publique du programme qui contient la logique d'exécution de
l'instruction. Le runtime utilise ce champ pour acheminer l'instruction vers le
programme approprié pour traitement.
Métadonnées de compte
Le tableau accounts de l'instruction est une liste ordonnée de structures
AccountMeta.
Des métadonnées doivent être fournies pour chaque compte avec lequel
l'instruction interagit. Le validateur utilise ces métadonnées pour déterminer
quelles transactions peuvent s'exécuter en parallèle. Les transactions qui
écrivent dans des comptes différents peuvent s'exécuter en parallèle.
Le diagramme ci-dessous représente une transaction contenant une seule
instruction. Le tableau accounts de l'instruction contient des métadonnées
pour deux comptes.
Une transaction avec une instruction. L'instruction contient deux structures AccountMeta dans son tableau accounts.
Chaque structure AccountMeta comporte trois champs :
- pubkey : l'adresse de clé publique du compte
- is_signer : défini sur
truesi le compte doit signer la transaction - is_writable : défini sur
truesi l'instruction modifie les données du compte
Pour savoir quels comptes une instruction nécessite, y compris lesquels doivent être modifiables, en lecture seule ou signer la transaction, vous devez vous référer à l'implémentation de l'instruction, telle que définie par le programme.
pub struct AccountMeta {/// An account's public key.pub pubkey: Pubkey,/// True if an `Instruction` requires a `Transaction` signature matching `pubkey`.pub is_signer: bool,/// True if the account data or metadata may be mutated during program execution.pub is_writable: bool,}
Données
Le champ data de l'instruction est un tableau d'octets qui indique au
programme quelle fonction invoquer et fournit les arguments pour cette fonction.
Les données commencent généralement par un discriminateur ou un ou plusieurs
octets d'index qui identifient la fonction cible, suivis des arguments
sérialisés. Le format d'encodage est défini par chaque programme (par exemple,
sérialisation Borsh ou disposition personnalisée).
Conventions d'encodage courantes :
- Programmes principaux (System, Stake, Vote) : utilisent un index de variante d'énumération sérialisé Bincode suivi d'arguments sérialisés.
- Programmes Anchor : utilisent un discriminateur de 8 octets (les 8
premiers octets du hachage SHA-256 de
"global:<function_name>") suivi d'arguments sérialisés Borsh.
Le runtime n'interprète pas le champ data. Il est transmis tel quel au point
d'entrée process_instruction du programme.
Instruction compilée
Lorsque les instructions sont sérialisées dans un message de transaction, elles
deviennent des structures
CompiledInstruction
qui remplacent toutes les clés publiques par des indices entiers compacts dans
le tableau account_keys du message.
Exemple : instruction de transfert SOL
L'exemple ci-dessous montre la structure d'une instruction de transfert SOL.
import { generateKeyPairSigner, lamports } from "@solana/kit";import { getTransferSolInstruction } from "@solana-program/system";// Generate sender and recipient keypairsconst sender = await generateKeyPairSigner();const recipient = await generateKeyPairSigner();// Define the amount to transferconst LAMPORTS_PER_SOL = 1_000_000_000n;const transferAmount = lamports(LAMPORTS_PER_SOL / 100n); // 0.01 SOL// Create a transfer instruction for transferring SOL from sender to recipientconst transferInstruction = getTransferSolInstruction({source: sender,destination: recipient.address,amount: transferAmount});console.log(JSON.stringify(transferInstruction, null, 2));
Le code ci-dessous montre la sortie des extraits de code précédents. Le format
différera entre les SDK, mais notez que chaque instruction contient les trois
mêmes éléments d'information requis : program_id,
accounts, data.
{"accounts": [{"address": "Hu28vRMGWpQXN56eaE7jRiDDRRz3vCXEs7EKHRfL6bC","role": 3,"signer": {"address": "Hu28vRMGWpQXN56eaE7jRiDDRRz3vCXEs7EKHRfL6bC","keyPair": {"privateKey": {},"publicKey": {}}}},{"address": "2mBY6CTgeyJNJDzo6d2Umipw2aGUquUA7hLdFttNEj7p","role": 1}],"programAddress": "11111111111111111111111111111111","data": {"0": 2,"1": 0,"2": 0,"3": 0,"4": 128,"5": 150,"6": 152,"7": 0,"8": 0,"9": 0,"10": 0,"11": 0}}
Les exemples ci-dessous montrent comment construire manuellement l'instruction
de transfert. (L'onglet Expanded Instruction est fonctionnellement équivalent
à l'onglet Instruction.)
En pratique, vous n'avez généralement pas besoin de construire une
Instruction manuellement. La plupart des programmes fournissent des
bibliothèques clientes avec des fonctions d'aide qui créent les instructions
pour vous. Si une bibliothèque n'est pas disponible, vous pouvez construire
l'instruction manuellement.
const transferAmount = 0.01; // 0.01 SOLconst transferInstruction = getTransferSolInstruction({source: sender,destination: recipient.address,amount: transferAmount * LAMPORTS_PER_SOL});
Is this page helpful?