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 zeigt
Eine
Transaction
besteht aus den folgenden Informationen:
signatures: Ein Array von Signaturenmessage: Transaktionsinformationen, einschließlich der Liste der zu verarbeitenden Anweisungen
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 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 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 Nachrichtaccount_keys: Ein Array von Kontoadressen, die von den Anweisungen der Transaktion benötigt werdenrecent_blockhash: Ein Blockhash, der als Zeitstempel für die Transaktion dientinstructions: 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.
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
Der header der Nachricht ist eine
MessageHeader
Struktur. Er enthält folgende Informationen:
num_required_signatures: Die Gesamtzahl der von der Transaktion benötigten Signaturennum_readonly_signed_accounts: Die Gesamtzahl der schreibgeschützten Konten, die Signaturen erfordernnum_readonly_unsigned_accounts: Die Gesamtzahl der schreibgeschützten Konten, die keine Signaturen erfordern
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 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:
- Signer + Beschreibbar
- Signer + Schreibgeschützt
- Kein Signer + Beschreibbar
- 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 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:
program_id_index: Ein Index, der auf eine Adresse imaccount_keysArray zeigt. Dieser Wert gibt die Adresse des Programms an, das die Anweisung verarbeitet.accounts: Ein Array von Indizes, die auf Adressen imaccount_keysArray zeigen. Jeder Index zeigt auf die Adresse eines Kontos, das für diese Anweisung erforderlich ist.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)
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 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 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));
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.
{"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?