Инструкции

Инструкции являются основным строительным блоком для взаимодействия с блокчейном Solana. Инструкция — это, по сути, публичная функция, которую может вызвать любой пользователь сети Solana. Каждая инструкция используется для выполнения определенного действия. Логика выполнения инструкций хранится в программах, где каждая программа определяет свой набор инструкций. Для взаимодействия с сетью Solana одна или несколько инструкций добавляются в транзакцию и отправляются в сеть для обработки.

Пример перевода SOL

На диаграмме ниже показано, как транзакции и инструкции работают вместе, чтобы пользователи могли взаимодействовать с сетью. В этом примере SOL переводится с одного аккаунта на другой.

Метаданные аккаунта отправителя указывают, что он должен подписать транзакцию. (Это позволяет System Program списать лампорты.) Оба аккаунта — отправителя и получателя — должны быть доступны для записи, чтобы их баланс лампортов мог измениться. Для выполнения этой инструкции кошелек отправителя отправляет транзакцию, содержащую его подпись, и сообщение с инструкцией перевода SOL.

Диаграмма перевода SOLДиаграмма перевода SOL

После отправки транзакции System Program обрабатывает инструкцию перевода и обновляет баланс лампортов обоих аккаунтов.

Диаграмма процесса перевода SOLДиаграмма процесса перевода 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 cluster
const rpc = createSolanaRpc("http://localhost:8899");
const rpcSubscriptions = createSolanaRpcSubscriptions("ws://localhost:8900");
// Generate sender and recipient keypairs
const 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 airdrop
await airdropFactory({ rpc, rpcSubscriptions })({
recipientAddress: sender.address,
lamports: lamports(LAMPORTS_PER_SOL), // 1 SOL
commitment: "confirmed"
});
// Check balance before transfer
const { 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 recipient
const transferInstruction = getTransferSolInstruction({
source: sender,
destination: recipient.address,
amount: transferAmount // 0.01 SOL in lamports
});
// Add the transfer instruction to a new transaction
const { 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 network
const signedTransaction =
await signTransactionMessageWithSigners(transactionMessage);
await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })(
signedTransaction,
{ commitment: "confirmed" }
);
const transactionSignature = getSignatureFromTransaction(signedTransaction);
// Check balance after transfer
const { 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 компонентаДиаграмма, изображающая транзакцию с инструкцией, разделенной на 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.Транзакция с одной инструкцией. Инструкция содержит две структуры 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 keypairs
const sender = await generateKeyPairSigner();
const recipient = await generateKeyPairSigner();
// Define the amount to transfer
const 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 recipient
const 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 SOL
const transferInstruction = getTransferSolInstruction({
source: sender,
destination: recipient.address,
amount: transferAmount * LAMPORTS_PER_SOL
});

Is this page helpful?

Содержание

Редактировать страницу