Інструкції

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

Приклад переказу SOL

Діаграма нижче показує, як транзакції та інструкції працюють разом, щоб дозволити користувачам взаємодіяти з мережею. У цьому прикладі SOL переказується з одного рахунку на інший.

Метадані рахунку відправника вказують, що він повинен підписати транзакцію. (Це дозволяє System Program відняти lamports.) Обидва рахунки — відправника та отримувача — повинні бути доступними для запису, щоб їхній баланс lamport міг змінитися. Для виконання цієї інструкції гаманець відправника надсилає транзакцію, що містить його підпис та повідомлення з інструкцією переказу SOL.

Діаграма переказу SOLДіаграма переказу SOL

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

Діаграма процесу переказу 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?

Зміст

Редагувати сторінку