Zusammenfassung
Eine Anweisung hat 3 Felder: program_id (welches Programm aufgerufen werden
soll), accounts (AccountMeta-Liste mit is_signer/is_writable-Flags) und
data (Byte-Array mit Daten, die das Programm interpretiert).
Anweisungsstruktur
Eine
Instruction
besteht aus drei Feldern:
program_id: Die ID des aufgerufenen Programms.accounts: Ein Array von Konto-Metadatendata: Ein Byte-Array mit zusätzlichen Daten für die Anweisung.
pub struct Instruction {/// Pubkey of the program that executes this instruction.pub program_id: Pubkey,/// Metadata describing accounts that should be passed to the program.pub accounts: Vec<AccountMeta>,/// Opaque data passed to the program for its own interpretation.pub data: Vec<u8>,}
Programm-ID
Die program_id der Anweisung ist
die öffentliche Schlüsseladresse des Programms, das die Ausführungslogik der
Anweisung enthält. Die Runtime verwendet dieses Feld, um die Anweisung zur
Verarbeitung an das richtige Programm weiterzuleiten.
Konto-Metadaten
Das accounts-Array der Anweisung ist eine geordnete Liste von
AccountMeta-Strukturen.
Für jedes Konto, mit dem die Anweisung interagiert, müssen Metadaten
bereitgestellt werden. Der Validator verwendet diese Metadaten, um zu bestimmen,
welche Transaktionen parallel ausgeführt werden können. Transaktionen, die in
verschiedene Konten schreiben, können parallel ausgeführt werden.
Das folgende Diagramm zeigt eine Transaktion, die eine einzelne Anweisung
enthält. Das accounts-Array der Anweisung enthält Metadaten für zwei Konten.
Eine Transaktion mit einer Anweisung. Die Anweisung enthält zwei AccountMeta-Strukturen in ihrem accounts-Array.
Jede AccountMeta-Struktur hat drei Felder:
- pubkey: Die öffentliche Schlüsseladresse des Kontos
- is_signer: Auf
truegesetzt, wenn das Konto die Transaktion signieren muss - is_writable: Auf
truegesetzt, wenn die Anweisung die Daten des Kontos ändert
Um zu wissen, welche Konten eine Anweisung benötigt, einschließlich welche beschreibbar, schreibgeschützt sein müssen oder die Transaktion signieren müssen, müssen Sie die Implementierung der Anweisung konsultieren, wie sie vom Programm definiert ist.
pub struct AccountMeta {/// An account's public key.pub pubkey: Pubkey,/// True if an `Instruction` requires a `Transaction` signature matching `pubkey`.pub is_signer: bool,/// True if the account data or metadata may be mutated during program execution.pub is_writable: bool,}
Daten
Das data-Feld der Anweisung ist ein Byte-Array, das dem Programm mitteilt,
welche Funktion aufgerufen werden soll, und die Argumente für diese Funktion
bereitstellt. Die Daten beginnen typischerweise mit einem Diskriminator oder
Index-Byte(s), der die Zielfunktion identifiziert, gefolgt von den
serialisierten Argumenten. Das Kodierungsformat wird von jedem Programm
definiert (zum Beispiel Borsh-Serialisierung oder ein benutzerdefiniertes
Layout).
Gängige Kodierungskonventionen:
- Kernprogramme (System, Stake, Vote): Verwenden einen Bincode-serialisierten Enum-Variantenindex, gefolgt von serialisierten Argumenten.
- Anchor-Programme: Verwenden einen 8-Byte-Diskriminator (die ersten 8 Bytes
des SHA-256-Hashs von
"global:<function_name>"), gefolgt von Borsh-serialisierten Argumenten.
Die Runtime interpretiert das data-Feld nicht. Es wird unverändert an den
process_instruction-Einstiegspunkt des Programms übergeben.
Kompilierte Anweisung
Wenn Anweisungen in eine Transaktionsnachricht serialisiert werden, werden sie
zu
CompiledInstruction-Strukturen,
die alle öffentlichen Schlüssel durch kompakte ganzzahlige Indizes in das
account_keys-Array der Nachricht ersetzen.
Beispiel: SOL-Transfer-Anweisung
Das folgende Beispiel zeigt die Struktur einer SOL-Transfer-Anweisung.
import { generateKeyPairSigner, lamports } from "@solana/kit";import { getTransferSolInstruction } from "@solana-program/system";// 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});console.log(JSON.stringify(transferInstruction, null, 2));
Der folgende Code zeigt die Ausgabe der vorherigen Code-Snippets. Das Format
unterscheidet sich zwischen den SDKs, aber beachten Sie, dass jede Anweisung
dieselben drei erforderlichen Informationen enthält:
program_id, accounts,
data.
{"accounts": [{"address": "Hu28vRMGWpQXN56eaE7jRiDDRRz3vCXEs7EKHRfL6bC","role": 3,"signer": {"address": "Hu28vRMGWpQXN56eaE7jRiDDRRz3vCXEs7EKHRfL6bC","keyPair": {"privateKey": {},"publicKey": {}}}},{"address": "2mBY6CTgeyJNJDzo6d2Umipw2aGUquUA7hLdFttNEj7p","role": 1}],"programAddress": "11111111111111111111111111111111","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}}
Die folgenden Beispiele zeigen, wie die Transfer-Anweisung manuell erstellt
wird. (Der Expanded Instruction-Tab ist funktional äquivalent zum
Instruction-Tab.)
In der Praxis müssen Sie normalerweise keine Instruction manuell
erstellen. Die meisten Programme bieten Client-Bibliotheken mit
Hilfsfunktionen, die die Anweisungen für Sie erstellen. Wenn keine Bibliothek
verfügbar ist, können Sie die Anweisung manuell erstellen.
const transferAmount = 0.01; // 0.01 SOLconst transferInstruction = getTransferSolInstruction({source: sender,destination: recipient.address,amount: transferAmount * LAMPORTS_PER_SOL});
Is this page helpful?