Транзакції
Для взаємодії з мережею Solana вам необхідно надіслати транзакцію. Транзакцію можна уявити як конверт, що містить кілька форм. Кожна форма — це інструкція, яка вказує мережі, що робити. Надсилання транзакції подібне до відправлення конверта поштою, щоб форми могли бути оброблені.
Приклад нижче показує спрощену версію двох транзакцій. Коли перша транзакція обробляється, вона виконає одну інструкцію. Коли друга транзакція обробляється, вона виконає три інструкції у послідовному порядку: спочатку інструкцію 1, потім інструкцію 2, а потім інструкцію 3.
Транзакції є атомарними: якщо одна інструкція не виконується, вся транзакція не вдається, і жодних змін не відбувається.
Спрощена діаграма, що показує дві транзакції
Transaction
складається з такої інформації:
signatures: Масив підписівmessage: Інформація про транзакцію, включаючи список інструкцій для обробки
Transaction
pub struct Transaction {#[wasm_bindgen(skip)]#[serde(with = "short_vec")]pub signatures: Vec<Signature>,#[wasm_bindgen(skip)]pub message: Message,}
Діаграма, що показує дві частини транзакції
Транзакції мають загальне обмеження розміру
1232
байти. Це обмеження включає як масив signatures, так і
структуру message.
Це обмеження походить від розміру максимальної одиниці передачі (MTU) IPv6 у 1280 байтів, мінус 48 байтів для мережевих заголовків (40 байтів IPv6 + 8 байтів заголовка).
Діаграма, що показує формат транзакції та обмеження розміру
Підписи
Масив signatures транзакції містить структури Signature. Кожен
Signature
має розмір 64 байти і створюється шляхом підписання Message транзакції за
допомогою приватного ключа облікового запису. Підпис повинен бути наданий для
кожного облікового запису підписувача, включеного до
будь-якої з інструкцій транзакції.
Перший підпис належить обліковому запису, який сплатить базову комісію транзакції і є підписом транзакції. Підпис транзакції можна використовувати для пошуку деталей транзакції в мережі.
Повідомлення
message транзакції — це структура
Message,
яка містить наступну інформацію:
header: Заголовок повідомленняaccount_keys: Масив адрес облікових записів, необхідних для інструкцій транзакціїrecent_blockhash: Хеш блоку, який діє як часова мітка для транзакціїinstructions: Масив інструкцій
Щоб заощадити місце, транзакція не зберігає дозволи для кожного облікового
запису окремо. Натомість дозволи облікових записів визначаються за допомогою
header та account_keys.
Message
pub struct Message {/// The message header, identifying signed and read-only `account_keys`.pub header: MessageHeader,/// All the account keys used by this transaction.#[serde(with = "short_vec")]pub account_keys: Vec<Pubkey>,/// The id of a recent ledger entry.pub recent_blockhash: Hash,/// Programs that will be executed in sequence and committed in/// one atomic transaction if all succeed.#[serde(with = "short_vec")]pub instructions: Vec<CompiledInstruction>,}
Заголовок
header повідомлення — це структура
MessageHeader.
Вона містить наступну інформацію:
num_required_signatures: Загальна кількість підписів, необхідних для транзакціїnum_readonly_signed_accounts: Загальна кількість облікових записів лише для читання, які потребують підписівnum_readonly_unsigned_accounts: Загальна кількість облікових записів лише для читання, які не потребують підписів
MessageHeader
pub struct MessageHeader {/// The number of signatures required for this message to be considered/// valid. The signers of those signatures must match the first/// `num_required_signatures` of [`Message::account_keys`].pub num_required_signatures: u8,/// The last `num_readonly_signed_accounts` of the signed keys are read-only/// accounts.pub num_readonly_signed_accounts: u8,/// The last `num_readonly_unsigned_accounts` of the unsigned keys are/// read-only accounts.pub num_readonly_unsigned_accounts: u8,}
Діаграма, що показує три частини заголовка повідомлення
Адреси облікових записів
account_keys
повідомлення — це масив адрес облікових записів, надісланий у
компактному форматі масиву.
Префікс масиву вказує на його довжину. Кожен елемент у масиві — це публічний
ключ, що вказує на обліковий запис, який використовується його інструкціями.
Масив accounts_keys повинен бути повним і строго впорядкованим наступним
чином:
- Підписувач + Доступний для запису
- Підписувач + Лише для читання
- Не підписувач + Доступний для запису
- Не підписувач + Лише для читання
Строге впорядкування дозволяє поєднувати масив account_keys з інформацією в
header повідомлення для визначення дозволів для кожного
облікового запису.
Діаграма, що показує порядок масиву адрес облікових записів
Останній блокхеш
recent_blockhash повідомлення — це хеш-значення, яке діє як часова мітка
транзакції та запобігає дублюванню транзакцій. Блокхеш закінчується після
150 блоків.
(Еквівалентно одній хвилині — за умови, що кожен блок триває 400 мс.) Після
закінчення терміну дії блоку транзакція стає недійсною і не може бути оброблена.
Метод RPC getLatestBlockhash дозволяє
отримати поточний блокхеш та висоту останнього блоку, на якому блокхеш буде
дійсним.
Інструкції
instructions
повідомлення — це масив усіх інструкцій, які потрібно обробити, надісланих у
компактному форматі масиву.
Префікс масиву вказує на його довжину. Кожен елемент у масиві є структурою
CompiledInstruction
і містить таку інформацію:
program_id_index: Індекс, що вказує на адресу в масивіaccount_keys. Це значення вказує на адресу програми, яка обробляє інструкцію.accounts: Масив індексів, що вказують на адреси в масивіaccount_keys. Кожен індекс вказує на адресу облікового запису, необхідного для цієї інструкції.data: Байтовий масив, що визначає, яку інструкцію викликати в програмі. Він також включає будь-які додаткові дані, необхідні для інструкції. (Наприклад, аргументи функції)
CompiledInstruction
pub struct CompiledInstruction {/// Index into the transaction keys array indicating the program account that executes this instruction.pub program_id_index: u8,/// Ordered indices into the transaction keys array indicating which accounts to pass to the program.#[serde(with = "short_vec")]pub accounts: Vec<u8>,/// The program input data.#[serde(with = "short_vec")]pub data: Vec<u8>,}
Компактний масив інструкцій
Приклад структури транзакції
Наступний приклад показує структуру транзакції, яка містить одну інструкцію переказу SOL.
import {createSolanaRpc,generateKeyPairSigner,lamports,createTransactionMessage,setTransactionMessageFeePayerSigner,setTransactionMessageLifetimeUsingBlockhash,appendTransactionMessageInstructions,pipe,signTransactionMessageWithSigners,getCompiledTransactionMessageDecoder} from "@solana/kit";import { getTransferSolInstruction } from "@solana-program/system";const rpc = createSolanaRpc("http://localhost:8899");const { value: latestBlockhash } = await rpc.getLatestBlockhash().send();// 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});// Create transaction messageconst transactionMessage = pipe(createTransactionMessage({ version: 0 }),(tx) => setTransactionMessageFeePayerSigner(sender, tx),(tx) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx),(tx) => appendTransactionMessageInstructions([transferInstruction], tx));const signedTransaction =await signTransactionMessageWithSigners(transactionMessage);// Decode the messageBytesconst compiledTransactionMessage =getCompiledTransactionMessageDecoder().decode(signedTransaction.messageBytes);console.log(JSON.stringify(compiledTransactionMessage, null, 2));
Console
Click to execute the code.
Код нижче показує вивід з попередніх фрагментів коду. Формат відрізняється між SDK, але зверніть увагу, що кожна інструкція містить однакову необхідну інформацію.
{"version": 0,"header": {"numSignerAccounts": 1,"numReadonlySignerAccounts": 0,"numReadonlyNonSignerAccounts": 1},"staticAccounts": ["HoCy8p5xxDDYTYWEbQZasEjVNM5rxvidx8AfyqA4ywBa","5T388jBjovy7d8mQ3emHxMDTbUF8b7nWvAnSiP3EAdFL","11111111111111111111111111111111"],"lifetimeToken": "EGCWPUEXhqHJWYBfDirq3mHZb4qDpATmYqBZMBy9TBC1","instructions": [{"programAddressIndex": 2,"accountIndices": [0, 1],"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}}]}
Після відправлення транзакції ви можете отримати її деталі, використовуючи підпис транзакції та метод RPC getTransaction. Відповідь матиме структуру, подібну до наступного фрагмента.
Ви також можете знайти транзакцію за допомогою Solana Explorer.
Transaction Data
{"blockTime": 1745196488,"meta": {"computeUnitsConsumed": 150,"err": null,"fee": 5000,"innerInstructions": [],"loadedAddresses": {"readonly": [],"writable": []},"logMessages": ["Program 11111111111111111111111111111111 invoke [1]","Program 11111111111111111111111111111111 success"],"postBalances": [989995000, 10000000, 1],"postTokenBalances": [],"preBalances": [1000000000, 0, 1],"preTokenBalances": [],"rewards": [],"status": {"Ok": null}},"slot": 13049,"transaction": {"message": {"header": {"numReadonlySignedAccounts": 0,"numReadonlyUnsignedAccounts": 1,"numRequiredSignatures": 1},"accountKeys": ["8PLdpLxkuv9Nt8w3XcGXvNa663LXDjSrSNon4EK7QSjQ","7GLg7bqgLBv1HVWXKgWAm6YoPf1LoWnyWGABbgk487Ma","11111111111111111111111111111111"],"recentBlockhash": "7ZCxc2SDhzV2bYgEQqdxTpweYJkpwshVSDtXuY7uPtjf","instructions": [{"accounts": [0, 1],"data": "3Bxs4NN8M2Yn4TLb","programIdIndex": 2,"stackHeight": null}],"indexToProgramIds": {}},"signatures": ["3jUKrQp1UGq5ih6FTDUUt2kkqUfoG2o4kY5T1DoVHK2tXXDLdxJSXzuJGY4JPoRivgbi45U2bc7LZfMa6C4R3szX"]},"version": "legacy"}
Is this page helpful?