Instructions
Les instructions sont l'élément fondamental pour interagir avec la blockchain Solana. Une instruction est essentiellement une fonction publique que tout utilisateur du réseau Solana peut appeler. Chaque instruction est utilisée pour effectuer une action spécifique. La logique d'exécution des instructions est stockée dans les programmes, où chaque programme définit son propre ensemble d'instructions. Pour interagir avec le réseau Solana, une ou plusieurs instructions sont ajoutées à une transaction et envoyées au réseau pour être traitées.
Exemple de transfert de SOL
Le diagramme ci-dessous montre comment les transactions et les instructions fonctionnent ensemble pour permettre aux utilisateurs d'interagir avec le réseau. Dans cet exemple, des SOL sont transférés d'un compte à un autre.
Les métadonnées du compte émetteur indiquent qu'il doit signer la transaction. (Cela permet au System Program de déduire des lamports.) Les comptes émetteur et destinataire doivent être modifiables, afin que leur solde en lamports puisse changer. Pour exécuter cette instruction, le portefeuille de l'émetteur envoie la transaction contenant sa signature et le message contenant l'instruction de transfert de SOL.
Diagramme de transfert SOL
Après l'envoi de la transaction, le System Program traite l'instruction de transfert et met à jour le solde en lamports des deux comptes.
Diagramme du processus de transfert SOL
L'exemple ci-dessous montre le code pertinent pour les diagrammes ci-dessus. (Voir l'instruction de transfert du System Program.)
import {airdropFactory,appendTransactionMessageInstructions,createSolanaRpc,createSolanaRpcSubscriptions,createTransactionMessage,generateKeyPairSigner,getSignatureFromTransaction,lamports,pipe,sendAndConfirmTransactionFactory,setTransactionMessageFeePayerSigner,setTransactionMessageLifetimeUsingBlockhash,signTransactionMessageWithSigners} from "@solana/kit";import { getTransferSolInstruction } from "@solana-program/system";// Create a connection to clusterconst rpc = createSolanaRpc("http://localhost:8899");const rpcSubscriptions = createSolanaRpcSubscriptions("ws://localhost:8900");// Generate sender and recipient keypairsconst sender = await generateKeyPairSigner();const recipient = await generateKeyPairSigner();const LAMPORTS_PER_SOL = 1_000_000_000n;const transferAmount = lamports(LAMPORTS_PER_SOL / 100n); // 0.01 SOL// Fund sender with airdropawait airdropFactory({ rpc, rpcSubscriptions })({recipientAddress: sender.address,lamports: lamports(LAMPORTS_PER_SOL), // 1 SOLcommitment: "confirmed"});// Check balance before transferconst { value: preBalance1 } = await rpc.getBalance(sender.address).send();const { value: preBalance2 } = await rpc.getBalance(recipient.address).send();// Create a transfer instruction for transferring SOL from sender to recipientconst transferInstruction = getTransferSolInstruction({source: sender,destination: recipient.address,amount: transferAmount // 0.01 SOL in lamports});// Add the transfer instruction to a new transactionconst { value: latestBlockhash } = await rpc.getLatestBlockhash().send();const transactionMessage = pipe(createTransactionMessage({ version: 0 }),(tx) => setTransactionMessageFeePayerSigner(sender, tx),(tx) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx),(tx) => appendTransactionMessageInstructions([transferInstruction], tx));// Send the transaction to the networkconst signedTransaction =await signTransactionMessageWithSigners(transactionMessage);await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })(signedTransaction,{ commitment: "confirmed" });const transactionSignature = getSignatureFromTransaction(signedTransaction);// Check balance after transferconst { value: postBalance1 } = await rpc.getBalance(sender.address).send();const { value: postBalance2 } = await rpc.getBalance(recipient.address).send();console.log("Sender prebalance:",Number(preBalance1) / Number(LAMPORTS_PER_SOL));console.log("Recipient prebalance:",Number(preBalance2) / Number(LAMPORTS_PER_SOL));console.log("Sender postbalance:",Number(postBalance1) / Number(LAMPORTS_PER_SOL));console.log("Recipient postbalance:",Number(postBalance2) / Number(LAMPORTS_PER_SOL));console.log("Transaction Signature:", transactionSignature);
Console
Click to execute the code.
Instructions
Diagramme représentant une transaction avec une instruction, décomposée en ses 3 composants
Une
Instruction
contient les informations suivantes :
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.
Instruction struct
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>,}
Program ID
Le program_id
de l'instruction est
l'adresse de clé publique du programme qui contient la logique métier de
l'instruction.
Métadonnées de compte
Le tableau accounts
de l'instruction est un tableau de structures
AccountMeta
.
Des métadonnées doivent être fournies pour chaque compte avec lequel
l'instruction interagit. (Cela permet aux transactions d'exécuter des
instructions en parallèle, tant qu'elles ne modifient pas le même compte.)
Le diagramme ci-dessous représente une transaction qui contient 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.
Les métadonnées du compte comprennent les informations suivantes :
- pubkey : L'adresse de clé publique du compte
- is_signer : Défini sur
true
si le compte doit signer la transaction - is_writable : Défini sur
true
si l'instruction modifie les données du compte
Pour savoir quels comptes une instruction requiert, 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.
AccountMeta
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 data
de l'instruction est un tableau d'octets qui spécifie laquelle des
instructions du programme invoquer. Il inclut également tous les arguments
requis par l'instruction.
Exemple de création d'instruction
L'exemple ci-dessous montre la structure d'une instruction de transfert de 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));
Console
Click to execute the code.
Le code ci-dessous montre la sortie des extraits de code précédents. Le format
diffère selon les SDK, mais remarquez 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 client avec des fonctions d'aide qui créent les instructions
pour vous. Si une bibliothèque n'est pas disponible, vous pouvez construire
manuellement l'instruction.
const transferAmount = 0.01; // 0.01 SOLconst transferInstruction = getTransferSolInstruction({source: sender,destination: recipient.address,amount: transferAmount * LAMPORTS_PER_SOL});
Is this page helpful?