Структура инструкции

Кратко

Инструкция содержит 3 поля: program_id (какую программу вызвать), accounts (список AccountMeta с флагами is_signer/is_writable) и data (массив байтов с данными, которые программа интерпретирует).

Структура инструкции

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>,
}

Program ID

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

Метаданные аккаунта

Массив accounts инструкции — это упорядоченный список AccountMeta структур. Метаданные должны быть указаны для каждого аккаунта, с которым взаимодействует инструкция. Validator использует эти метаданные, чтобы определить, какие транзакции могут выполняться параллельно. Транзакции, которые записывают данные в разные аккаунты, могут выполняться одновременно.

На схеме ниже показана транзакция, содержащая одну инструкцию. Массив accounts инструкции содержит метаданные для двух аккаунтов.

Транзакция с одной инструкцией. Инструкция содержит две структуры AccountMeta в своём массиве accounts.Транзакция с одной инструкцией. Инструкция содержит две структуры AccountMeta в своём массиве accounts.

Каждая AccountMeta содержит три поля:

  • 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 инструкции — это массив байтов, который сообщает программе, какую функцию вызвать и какие аргументы ей передать. Обычно данные начинаются с дискриминатора или байта(ов) индекса, который определяет целевую функцию, а затем следуют сериализованные аргументы. Формат кодирования определяется каждой программой отдельно (например, сериализация Borsh или собственная схема).

Общие соглашения по кодированию:

  • Core-программы (System, Stake, Vote): используют индекс варианта enum, сериализованный через Bincode, за которым следуют сериализованные аргументы.
  • Anchor-программы: используют 8-байтовый дискриминатор (первые 8 байтов SHA-256 хэша "global:<function_name>"), за которым следуют аргументы, сериализованные через Borsh.

Среда выполнения не интерпретирует поле data. Оно передаётся как есть в entrypoint программы process_instruction.

Скомпилированная инструкция

Когда инструкции сериализуются в сообщение транзакции, они становятся CompiledInstruction структурами, в которых все публичные ключи заменяются компактными целочисленными индексами в массиве account_keys сообщения.

Пример: инструкция перевода SOL

Пример ниже показывает структуру инструкции перевода 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?

Содержание

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

Управляется

© 2026 Solana Foundation.
Все права защищены.
Связаться с нами