Transaktionen

Um mit dem Solana-Netzwerk zu interagieren, müssen Sie eine Transaktion senden. Sie können sich eine Transaktion wie einen Umschlag vorstellen, der mehrere Formulare enthält. Jedes Formular ist eine Anweisung, die dem Netzwerk mitteilt, was zu tun ist. Das Senden der Transaktion ist wie das Versenden des Umschlags, damit die Formulare verarbeitet werden können.

Das folgende Beispiel zeigt eine vereinfachte Version von zwei Transaktionen. Wenn die erste Transaktion verarbeitet wird, führt sie eine einzelne Anweisung aus. Wenn die zweite Transaktion verarbeitet wird, führt sie drei Anweisungen in sequentieller Reihenfolge aus: zuerst Anweisung 1, gefolgt von Anweisung 2, gefolgt von Anweisung 3.

Transaktionen sind atomar: Wenn eine einzelne Anweisung fehlschlägt, wird die gesamte Transaktion fehlschlagen und es werden keine Änderungen vorgenommen.

Ein vereinfachtes Diagramm, das zwei Transaktionen zeigtEin vereinfachtes Diagramm, das zwei Transaktionen zeigt

Eine Transaction besteht aus den folgenden Informationen:

  • signatures: Ein Array von Signaturen
  • message: Transaktionsinformationen, einschließlich der Liste der zu verarbeitenden Anweisungen
Transaction
pub struct Transaction {
#[wasm_bindgen(skip)]
#[serde(with = "short_vec")]
pub signatures: Vec<Signature>,
#[wasm_bindgen(skip)]
pub message: Message,
}

Diagramm, das die zwei Teile einer Transaktion zeigtDiagramm, das die zwei Teile einer Transaktion zeigt

Transaktionen haben eine Gesamtgrößenbegrenzung von 1232 Bytes. Diese Begrenzung umfasst sowohl das signatures-Array als auch die message-Struktur.

Diese Begrenzung stammt von der IPv6 Maximum Transmission Unit (MTU) Größe von 1280 Bytes, abzüglich 48 Bytes für Netzwerk-Header (40 Bytes IPv6 + 8 Bytes Header).

Diagramm, das das Transaktionsformat und Größenbegrenzungen zeigtDiagramm, das das Transaktionsformat und Größenbegrenzungen zeigt

Signaturen

Das signaturesArray der Transaktion enthält SignatureStrukturen. Jede Signature ist 64 Bytes groß und wird durch Signieren des Message der Transaktion mit dem privaten Schlüssel des Kontos erstellt. Eine Signatur muss für jedes Signer-Konto bereitgestellt werden, das in einer der Anweisungen der Transaktion enthalten ist.

Die erste Signatur gehört zu dem Konto, das die Basisgebühr der Transaktion bezahlt und ist die Transaktionssignatur. Die Transaktionssignatur kann verwendet werden, um die Details der Transaktion im Netzwerk nachzuschlagen.

Nachricht

Die message der Transaktion ist eine Message Struktur, die folgende Informationen enthält:

  • header: Der Header der Nachricht
  • account_keys: Ein Array von Kontoadressen, die von den Anweisungen der Transaktion benötigt werden
  • recent_blockhash: Ein Blockhash, der als Zeitstempel für die Transaktion dient
  • instructions: Ein Array von Anweisungen

Um Speicherplatz zu sparen, speichert die Transaktion nicht die Berechtigungen für jedes Konto einzeln. Stattdessen werden die Kontoberechtigungen mithilfe des header und account_keys bestimmt.

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

Der header der Nachricht ist eine MessageHeader Struktur. Er enthält folgende Informationen:

  • num_required_signatures: Die Gesamtzahl der von der Transaktion benötigten Signaturen
  • num_readonly_signed_accounts: Die Gesamtzahl der schreibgeschützten Konten, die Signaturen erfordern
  • num_readonly_unsigned_accounts: Die Gesamtzahl der schreibgeschützten Konten, die keine Signaturen erfordern
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,
}

Diagramm, das die drei Teile des Nachrichtenheaders zeigtDiagramm, das die drei Teile des Nachrichtenheaders zeigt

Kontoadressen

Das account_keys der Nachricht ist ein Array von Kontoadressen, das im Kompakt-Array-Format gesendet wird. Das Präfix des Arrays gibt seine Länge an. Jedes Element im Array ist ein öffentlicher Schlüssel, der auf ein von seinen Anweisungen verwendetes Konto verweist. Das accounts_keysArray muss vollständig und streng in folgender Reihenfolge angeordnet sein:

  1. Signer + Beschreibbar
  2. Signer + Schreibgeschützt
  3. Kein Signer + Beschreibbar
  4. Kein Signer + Schreibgeschützt

Die strenge Anordnung ermöglicht es, das account_keysArray mit den Informationen im header der Nachricht zu kombinieren, um die Berechtigungen für jedes Konto zu bestimmen.

Diagramm, das die Reihenfolge des Kontenadressenfeldes zeigtDiagramm, das die Reihenfolge des Kontenadressenfeldes zeigt

Aktueller Blockhash

Der recent_blockhash der Nachricht ist ein Hash-Wert, der als Zeitstempel für die Transaktion dient und doppelte Transaktionen verhindert. Ein Blockhash läuft nach 150 Blöcken ab. (Entspricht einer Minute – unter der Annahme, dass jeder Block 400ms dauert.) Nach Ablauf des Blocks ist die Transaktion abgelaufen und kann nicht mehr verarbeitet werden.

Die RPC-Methode getLatestBlockhash ermöglicht es dir, den aktuellen Blockhash und die letzte Blockhöhe zu erhalten, bei der der Blockhash noch gültig sein wird.

Anweisungen

Das instructions der Nachricht ist ein Array aller zu verarbeitenden Anweisungen, gesendet im kompakten Array-Format. Das Präfix des Arrays gibt seine Länge an. Jedes Element im Array ist eine CompiledInstruction Struktur und enthält folgende Informationen:

  1. program_id_index: Ein Index, der auf eine Adresse im account_keys Array zeigt. Dieser Wert gibt die Adresse des Programms an, das die Anweisung verarbeitet.
  2. accounts: Ein Array von Indizes, die auf Adressen im account_keys Array zeigen. Jeder Index zeigt auf die Adresse eines Kontos, das für diese Anweisung erforderlich ist.
  3. data: Ein Byte-Array, das angibt, welche Anweisung im Programm aufgerufen werden soll. Es enthält auch alle zusätzlichen Daten, die von der Anweisung benötigt werden. (Zum Beispiel Funktionsargumente)
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>,
}

Kompaktes Array von AnweisungenKompaktes Array von Anweisungen

Beispiel einer Transaktionsstruktur

Das folgende Beispiel zeigt die Struktur einer Transaktion, die eine einzelne SOL-Überweisungsanweisung enthält.

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.

Der folgende Code zeigt die Ausgabe der vorherigen Codeausschnitte. Das Format unterscheidet sich zwischen den SDKs, aber beachte, dass jede Anweisung die gleichen erforderlichen Informationen enthält.

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

Nachdem eine Transaktion übermittelt wurde, können Sie ihre Details mithilfe der Transaktionssignatur und der getTransaction RPC-Methode abrufen. Die Antwort wird eine Struktur ähnlich dem folgenden Ausschnitt haben.

Sie können die Transaktion auch über den Solana Explorer finden.

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?

Inhaltsverzeichnis

Seite bearbeiten

Verwaltet von

© 2025 Solana Foundation.
Alle Rechte vorbehalten.
Verbinden Sie sich