Transakcje

Aby wchodzić w interakcje z siecią Solana, musisz wysłać transakcję. Możesz myśleć o transakcji jak o kopercie, która zawiera kilka formularzy. Każdy formularz to instrukcja, która mówi sieci, co ma zrobić. Wysłanie transakcji jest jak wysłanie koperty, aby formularze mogły zostać przetworzone.

Poniższy przykład pokazuje uproszczoną wersję dwóch transakcji. Gdy pierwsza transakcja zostanie przetworzona, wykona pojedynczą instrukcję. Gdy druga transakcja zostanie przetworzona, wykona trzy instrukcje w kolejności sekwencyjnej: najpierw instrukcję 1, następnie instrukcję 2, a na końcu instrukcję 3.

Transakcje są atomowe: jeśli pojedyncza instrukcja się nie powiedzie, cała transakcja zakończy się niepowodzeniem i żadne zmiany nie zostaną wprowadzone.

Uproszczony diagram przedstawiający dwie transakcjeUproszczony diagram przedstawiający dwie transakcje

A Transaction składa się z następujących informacji:

  • signatures: Tablica podpisów
  • message: Informacje o transakcji, w tym lista instrukcji do przetworzenia
Transaction
pub struct Transaction {
#[wasm_bindgen(skip)]
#[serde(with = "short_vec")]
pub signatures: Vec<Signature>,
#[wasm_bindgen(skip)]
pub message: Message,
}

Diagram przedstawiający dwie części transakcjiDiagram przedstawiający dwie części transakcji

Transakcje mają całkowity limit rozmiaru wynoszący 1232 bajtów. Limit ten obejmuje zarówno tablicę signatures, jak i strukturę message.

Ten limit wynika z maksymalnej jednostki transmisji (MTU) IPv6 wynoszącej 1280 bajtów, pomniejszonej o 48 bajtów na nagłówki sieciowe (40 bajtów IPv6 + 8 bajtów nagłówka).

Diagram przedstawiający format transakcji i limity rozmiaruDiagram przedstawiający format transakcji i limity rozmiaru

Podpisy

Tablica signatures transakcji zawiera struktury Signature. Każda Signature ma 64 bajty i jest tworzona przez podpisanie Message transakcji za pomocą prywatnego klucza konta. Podpis musi być dostarczony dla każdego konta podpisującego uwzględnionego w dowolnej z instrukcji transakcji.

Pierwszy podpis należy do konta, które opłaci opłatę bazową transakcji i jest podpisem transakcji. Podpis transakcji może być użyty do wyszukiwania szczegółów transakcji w sieci.

Wiadomość

message transakcji to Message struktura zawierająca następujące informacje:

  • header: Nagłówek wiadomości header
  • account_keys: Tablica adresów kont wymaganych przez instrukcje transakcji
  • recent_blockhash: blockhash, który działa jako znacznik czasu dla transakcji
  • instructions: Tablica instrukcji

Aby zaoszczędzić miejsce, transakcja nie przechowuje uprawnień dla każdego konta indywidualnie. Zamiast tego uprawnienia kont są określane za pomocą header i 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>,
}

Nagłówek

header wiadomości to MessageHeader struktura zawierająca następujące informacje:

  • num_required_signatures: Całkowita liczba podpisów wymaganych przez transakcję
  • num_readonly_signed_accounts: Całkowita liczba kont tylko do odczytu, które wymagają podpisów
  • num_readonly_unsigned_accounts: Całkowita liczba kont tylko do odczytu, które nie wymagają podpisów
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,
}

Diagram przedstawiający trzy części nagłówka wiadomościDiagram przedstawiający trzy części nagłówka wiadomości

Adresy kont

account_keys wiadomości to tablica adresów kont, przesyłana w kompaktowym formacie tablicy. Prefiks tablicy wskazuje jej długość. Każdy element w tablicy to klucz publiczny, wskazujący na konto używane przez jego instrukcje. Tablica accounts_keys musi być kompletna i ściśle uporządkowana w następujący sposób:

  1. Podpisujący + Zapis
  2. Podpisujący + Tylko do odczytu
  3. Nie podpisujący + Zapis
  4. Nie podpisujący + Tylko do odczytu

Ścisłe uporządkowanie pozwala na połączenie tablicy account_keys z informacjami w header wiadomości w celu określenia uprawnień dla każdego konta.

Diagram przedstawiający kolejność tablicy adresów kontDiagram przedstawiający kolejność tablicy adresów kont

Ostatni blockhash

recent_blockhash wiadomości to wartość hash, która działa jako znacznik czasu transakcji i zapobiega duplikatom transakcji. Blockhash wygasa po 150 blokach. (Odpowiada to jednej minucie — zakładając, że każdy blok trwa 400 ms). Po wygaśnięciu bloku transakcja wygasa i nie może zostać przetworzona.

Metoda RPC getLatestBlockhash pozwala uzyskać aktualny blockhash oraz ostatnią wysokość bloku, przy której blockhash będzie ważny.

Instrukcje

instructions wiadomości to tablica wszystkich instrukcji do przetworzenia, wysyłana w kompaktowym formacie tablicy. Prefiks tablicy wskazuje jej długość. Każdy element tablicy to struktura CompiledInstruction i zawiera następujące informacje:

  1. program_id_index: Indeks wskazujący adres w tablicy account_keys. Wartość ta wskazuje adres programu, który przetwarza instrukcję.
  2. accounts: Tablica indeksów wskazujących adresy w tablicy account_keys. Każdy indeks wskazuje adres konta wymaganego dla tej instrukcji.
  3. data: Tablica bajtów określająca, którą instrukcję wywołać w programie. Zawiera również wszelkie dodatkowe dane wymagane przez instrukcję (na przykład argumenty funkcji).
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>,
}

Kompaktowa tablica instrukcjiKompaktowa tablica instrukcji

Przykładowa struktura transakcji

Poniższy przykład pokazuje strukturę transakcji zawierającej pojedynczą instrukcję transferu 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 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
});
// Create transaction message
const transactionMessage = pipe(
createTransactionMessage({ version: 0 }),
(tx) => setTransactionMessageFeePayerSigner(sender, tx),
(tx) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx),
(tx) => appendTransactionMessageInstructions([transferInstruction], tx)
);
const signedTransaction =
await signTransactionMessageWithSigners(transactionMessage);
// Decode the messageBytes
const compiledTransactionMessage =
getCompiledTransactionMessageDecoder().decode(signedTransaction.messageBytes);
console.log(JSON.stringify(compiledTransactionMessage, null, 2));
Console
Click to execute the code.

Kod poniżej pokazuje wynik z poprzednich fragmentów kodu. Format różni się między SDK, ale zauważ, że każda instrukcja zawiera te same wymagane informacje.

{
"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
}
}
]
}

Po przesłaniu transakcji możesz pobrać jej szczegóły, używając sygnatury transakcji oraz metody RPC getTransaction. Odpowiedź będzie miała strukturę podobną do poniższego fragmentu.

Możesz również znaleźć transakcję, korzystając z 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?

Spis treści

Edytuj stronę

Zarządzane przez

© 2025 Solana Foundation.
Wszelkie prawa zastrzeżone.
Bądź na bieżąco