Инструкции
Инструкции являются основным строительным блоком для взаимодействия с блокчейном Solana. Инструкция — это, по сути, публичная функция, которую может вызвать любой пользователь сети Solana. Каждая инструкция используется для выполнения определенного действия. Логика выполнения инструкций хранится в программах, где каждая программа определяет свой набор инструкций. Для взаимодействия с сетью Solana одна или несколько инструкций добавляются в транзакцию и отправляются в сеть для обработки.
Пример перевода SOL
На диаграмме ниже показано, как транзакции и инструкции работают вместе, чтобы пользователи могли взаимодействовать с сетью. В этом примере SOL переводится с одного аккаунта на другой.
Метаданные аккаунта отправителя указывают, что он должен подписать транзакцию. (Это позволяет System Program списать лампорты.) Оба аккаунта — отправителя и получателя — должны быть доступны для записи, чтобы их баланс лампортов мог измениться. Для выполнения этой инструкции кошелек отправителя отправляет транзакцию, содержащую его подпись, и сообщение с инструкцией перевода SOL.
Диаграмма перевода SOL
После отправки транзакции System Program обрабатывает инструкцию перевода и обновляет баланс лампортов обоих аккаунтов.
Диаграмма процесса перевода SOL
Пример ниже показывает код, относящийся к приведенным выше диаграммам. (См. инструкцию перевода в 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.
Инструкции
Диаграмма, изображающая транзакцию с инструкцией, разделенной на 3 компонента
Инструкция
Instruction
состоит из следующей информации:
program_id
: ID программы, которая вызывается.accounts
: Массив метаданных аккаунтовdata
: Массив байтов с дополнительными [данными], которые используются инструкцией.
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>,}
ID программы
program_id
инструкции — это
публичный ключ программы, которая содержит бизнес-логику инструкции.
Метаданные аккаунтов
Массив accounts
инструкции — это массив структур
AccountMeta
.
Метаданные должны быть предоставлены для каждого аккаунта, с которым
взаимодействует инструкция. (Это позволяет транзакции выполнять инструкции
параллельно, если они не изменяют один и тот же аккаунт.)
На диаграмме ниже показана транзакция, содержащая одну инструкцию. Массив
accounts
инструкции содержит метаданные для двух аккаунтов.
Транзакция с одной инструкцией. Инструкция содержит две структуры AccountMeta в массиве accounts.
Метаданные аккаунтов включают следующую информацию:
- pubkey: Публичный ключ аккаунта
- is_signer: Установлено в
true
, если аккаунт должен подписать транзакцию - is_writable: Установлено в
true
, если инструкция изменяет данные аккаунта
Чтобы узнать, какие аккаунты требуются для инструкции, включая те, которые должны быть изменяемыми, только для чтения или подписывать транзакцию, необходимо обратиться к реализации инструкции, определенной программой.
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,}
Данные
data
инструкции — это массив байтов, который указывает, какую инструкцию
программы вызвать. Он также включает любые аргументы, необходимые для
инструкции.
Пример создания инструкции
Пример ниже показывает структуру инструкции перевода 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.
Код ниже показывает вывод из предыдущих фрагментов кода. Формат будет отличаться
между SDK, но обратите внимание, что каждая инструкция содержит три одинаковых
обязательных элемента: 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}}
Примеры ниже показывают, как вручную создать инструкцию перевода. (Вкладка
Expanded Instruction
функционально эквивалентна вкладке Instruction
.)
На практике вам обычно не нужно вручную создавать Instruction
. Большинство
программ предоставляют клиентские библиотеки с вспомогательными функциями,
которые создают инструкции за вас. Если библиотека недоступна, вы можете
вручную создать инструкцию.
const transferAmount = 0.01; // 0.01 SOLconst transferInstruction = getTransferSolInstruction({source: sender,destination: recipient.address,amount: transferAmount * LAMPORTS_PER_SOL});
Is this page helpful?