İşlem yapısı

Özet

Bir işlem, imzalar + bir mesajdan oluşur. Mesaj bir başlık, hesap adresleri, güncel blok hash'i ve derlenmiş talimatlar içerir. Maksimum serileştirilmiş boyut: 1.232 bayt.

Bir Transaction iki üst düzey alana sahiptir:

  • signatures: İmza dizisi
  • message: İşlenecek talimatların listesi dahil olmak üzere işlem bilgileri
Transaction
pub struct Transaction {
pub signatures: Vec<Signature>,
pub message: Message,
}

Bir işlemin iki bölümünü gösteren diyagramBir işlemin iki bölümünü gösteren diyagram

Bir işlemin toplam serileştirilmiş boyutu PACKET_DATA_SIZE değerini (1.232 bayt) aşmamalıdır. Bu sınır, 1.280 bayta (IPv6 minimum MTU) eşittir ve ağ başlıkları için 48 bayt (40 bayt IPv6 + 8 bayt fragment başlığı) çıkarılmıştır. 1.232 bayt hem signatures dizisini hem de message yapısını içerir.

İşlem formatını ve boyut sınırlarını gösteren diyagramİşlem formatını ve boyut sınırlarını gösteren diyagram

İmzalar

signatures alanı, kompakt kodlanmış bir Signature değerleri dizisidir. Her Signature, imzalayan hesabın özel anahtarıyla imzalanmış, serileştirilmiş Message'ın 64 baytlık bir Ed25519 imzasıdır. İşlemin talimatları tarafından referans verilen her imzalayan hesap için bir imza gereklidir.

Dizideki ilk imza, işlem temel ücret ve önceliklendirme ücretini ödeyen hesap olan ücret ödeyicisine aittir. Bu ilk imza aynı zamanda ağda işlemi aramak için kullanılan işlem kimliği olarak da hizmet eder. İşlem kimliği genellikle işlem imzası olarak adlandırılır.

Ücret ödeyen gereksinimleri:

  • Mesajdaki ilk hesap (indeks 0) olmalı ve imzalayan olmalıdır.
  • System Program'a ait bir hesap veya nonce hesabı olmalıdır (validate_fee_payer tarafından doğrulanır).
  • rent_exempt_minimum + total_fee tutarını karşılayacak yeterli lamport içermelidir; aksi takdirde işlem InsufficientFundsForFee hatası ile başarısız olur.

Mesaj

message alanı, işlemin yükünü içeren bir Message yapısıdır:

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

Başlık

header alanı, account_keys dizisini izin gruplarına bölen üç u8 alanına sahip bir MessageHeader yapısıdır:

  • num_required_signatures: İşlem için gereken toplam imza sayısı.
  • num_readonly_signed_accounts: Salt okunur olan imzalı hesap sayısı.
  • num_readonly_unsigned_accounts: Salt okunur olan imzasız hesap sayısı.
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,
}

Mesaj başlığının üç bölümünü gösteren diyagramMesaj başlığının üç bölümünü gösteren diyagram

Hesap adresleri

account_keys alanı, kompakt kodlanmış bir public key dizisidir. Her giriş, işlemin talimatlarından en az biri tarafından kullanılan bir hesabı tanımlar. Dizi her hesabı içermeli ve şu katı sıralamayı izlemelidir:

  1. İmzalayan + Yazılabilir
  2. İmzalayan + Salt okunur
  3. İmzalayan olmayan + Yazılabilir
  4. İmzalayan olmayan + Salt okunur

Bu katı sıralama, account_keys dizisinin mesajın header alanındaki üç sayımla birleştirilerek, hesap başına metadata bayrakları saklamadan her hesap için izinlerin belirlenmesini sağlar. Başlık sayımları, diziyi yukarıda listelenen dört izin grubuna böler.

Hesap adresleri dizisinin sırasını gösteren diyagramHesap adresleri dizisinin sırasını gösteren diyagram

Son blok hash'i

recent_blockhash alanı, iki amaca hizmet eden 32 baytlık bir hash'tir:

  1. Zaman damgası: işlemin yakın zamanda oluşturulduğunu kanıtlar.
  2. Tekrar önleme: aynı işlemin iki kez işlenmesini önler.

Bir blok hash'i 150 slot sonra geçerliliğini yitirir. İşlem ulaştığında blok hash'i artık geçerli değilse, geçerli bir dayanıklı nonce işlemi olmadığı sürece BlockhashNotFound ile reddedilir.

getLatestBlockhash RPC metodu, mevcut blok hash'ini ve blok hash'inin geçerli olacağı son blok yüksekliğini almanızı sağlar.

Talimatlar

instructions alanı, CompiledInstruction yapılarının kompakt kodlanmış bir dizisidir. Her CompiledInstruction, tam public key yerine account_keys dizisindeki indeks ile hesaplara referans verir. Şunları içerir:

  1. program_id_index: Çağrılacak programı tanımlayan account_keys içindeki indeks.
  2. accounts: Programa iletilecek hesapları belirten account_keys içindeki indeksler dizisi.
  3. data: Talimat ayırıcısını ve serileştirilmiş argümanları içeren bayt dizisi.
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>,
}

Talimatların kompakt dizisiTalimatların kompakt dizisi

İşlem ikili formatı

İşlemler kompakt bir kodlama şeması kullanılarak serileştirilir. Tüm değişken uzunluklu diziler (imzalar, hesap anahtarları, talimatlar) compact-u16 uzunluk kodlaması ile öneklenir. Bu format, 0-127 değerleri için 1 bayt ve daha büyük değerler için 2-3 bayt kullanır.

Legacy işlem düzeni (kablo üzerinde):

AlanBoyutAçıklama
num_signatures1-3 bayt (compact-u16)İmza sayısı
signaturesnum_signatures x 64 baytEd25519 imzaları
num_required_signatures1 baytMessageHeader alan 1
num_readonly_signed1 baytMessageHeader alan 2
num_readonly_unsigned1 baytMessageHeader alan 3
num_account_keys1-3 bayt (compact-u16)Statik hesap anahtarı sayısı
account_keysnum_account_keys x 32 baytPublic key'ler
recent_blockhash32 baytBlok hash'i
num_instructions1-3 bayt (compact-u16)Talimat sayısı
instructionsdeğişkenDerlenmiş talimatlar dizisi

Her derlenmiş talimat şu şekilde serileştirilir:

AlanBoyutAçıklama
program_id_index1 baytHesap anahtarlarına indeks
num_accounts1-3 bayt (compact-u16)Hesap indeksi sayısı
account_indicesnum_accounts x 1 baytHesap anahtarı indeksleri
data_len1-3 bayt (compact-u16)Talimat verisi uzunluğu
datadata_len baytOpak talimat verisi

Boyut hesaplama

PACKET_DATA_SIZE = 1.232 bayt olduğunda, kullanılabilir alan şu şekilde hesaplanabilir:

Total = 1232 bytes
- compact-u16(num_sigs) # 1 byte
- num_sigs * 64 # signature bytes
- 3 # message header
- compact-u16(num_keys) # 1 byte
- num_keys * 32 # account key bytes
- 32 # recent blockhash
- compact-u16(num_ixs) # 1 byte
- sum(instruction_sizes) # per-instruction overhead + data

Örnek: SOL transfer işlemi

Aşağıdaki diyagram, kullanıcıların ağ ile etkileşime girmesini sağlamak için işlemlerin ve talimatların birlikte nasıl çalıştığını göstermektedir. Bu örnekte, SOL bir hesaptan diğerine aktarılmaktadır.

Gönderen hesabın metaverisi, işlem için imzalaması gerektiğini belirtir. Bu, System Program'ın lamport düşmesine izin verir. Lamport bakiyelerinin değişebilmesi için hem gönderen hem de alıcı hesapların yazılabilir olması gerekir. Bu talimatı yürütmek için gönderenin cüzdanı, imzasını ve SOL transfer talimatını içeren mesajı içeren işlemi gönderir.

SOL transfer diyagramıSOL transfer diyagramı

İşlem gönderildikten sonra, System Program transfer talimatını işler ve her iki hesabın lamport bakiyesini günceller.

SOL transfer işlem diyagramıSOL transfer işlem diyagramı

Aşağıdaki örnek, yukarıdaki diyagramlarla ilgili kodu göstermektedir. System Program'ın transfer fonksiyonuna bakın.

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.

Aşağıdaki örnek, tek bir SOL transfer talimatı içeren bir işlemin yapısını göstermektedir.

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.

Aşağıdaki kod, önceki kod parçacıklarından elde edilen çıktıyı gösterir. Format SDK'lar arasında farklılık gösterir, ancak her talimatın aynı gerekli bilgileri içerdiğine dikkat edin.

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

İşlem detaylarını getirme

Gönderimden sonra, işlem imzasını ve getTransaction RPC metodunu kullanarak işlem detaylarını alın.

İşlemi Solana Explorer kullanarak da bulabilirsiniz.

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?

İçindekiler

Sayfayı Düzenle

Yönetici

© 2026 Solana Vakfı.
Tüm hakları saklıdır.
Bağlanın