Podsumowanie
Instrukcja posiada 3 pola: program_id (określa, który program wywołać),
accounts (lista AccountMeta z flagami is_signer/is_writable) oraz data
(tablica bajtów z danymi interpretowanymi przez program).
Struktura instrukcji
Instrukcja
Instruction
składa się z trzech pól:
program_id: ID programu, który jest wywoływany.accounts: Tablica metadanych kontdata: Tablica bajtów z dodatkowymi danymi, które zostaną użyte przez instrukcję.
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>,}
Program ID
program_id instrukcji to adres
publiczny programu, który zawiera logikę wykonania instrukcji. Środowisko
uruchomieniowe wykorzystuje to pole, aby przekierować instrukcję do
odpowiedniego programu do przetworzenia.
Metadane kont
Tablica accounts instrukcji to uporządkowana lista struktur
AccountMeta.
Metadane muszą być podane dla każdego konta, z którym instrukcja wchodzi w
interakcję. Validator wykorzystuje te metadane, aby określić, które transakcje
mogą być wykonywane równolegle. Transakcje zapisujące do różnych kont mogą być
wykonywane jednocześnie.
Poniższy diagram przedstawia transakcję zawierającą jedną instrukcję. Tablica
accounts instrukcji zawiera metadane dla dwóch kont.
Transakcja z jedną instrukcją. Instrukcja zawiera dwie struktury AccountMeta w swojej tablicy accounts.
Każda AccountMeta posiada trzy pola:
- pubkey: Publiczny adres konta
- is_signer: Ustawione na
true, jeśli konto musi podpisać transakcję - is_writable: Ustawione na
true, jeśli instrukcja modyfikuje dane konta
Aby dowiedzieć się, jakie konta są wymagane przez instrukcję, w tym które muszą być zapisywalne, tylko do odczytu lub muszą podpisać transakcję, należy odwołać się do implementacji instrukcji, zgodnie z definicją programu.
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,}
Dane
Pole data instrukcji to tablica bajtów, która informuje program, którą funkcję
wywołać i przekazuje argumenty do tej funkcji. Dane typowo zaczynają się od
bajtu (lub bajtów) dyskryminatora lub indeksu, który identyfikuje docelową
funkcję, a następnie znajdują się zserializowane argumenty. Format kodowania
definiowany jest przez każdy program indywidualnie (na przykład serializacja
Borsh lub własny układ).
Typowe konwencje kodowania:
- Programy rdzeniowe (System, Stake, Vote): Używają wariantu enum zserializowanego przez Bincode jako indeks, po którym następują zserializowane argumenty.
- Programy Anchor: Używają 8-bajtowego dyskryminatora (pierwsze 8 bajtów
skrótu SHA-256 z
"global:<function_name>"), po którym następują argumenty zserializowane przez Borsh.
Środowisko uruchomieniowe nie interpretuje pola data. Jest ono przekazywane w
niezmienionej postaci do punktu wejścia programu process_instruction.
Skompilowana instrukcja
Gdy instrukcje są serializowane do wiadomości transakcji, stają się
CompiledInstruction
strukturami, które zastępują wszystkie klucze publiczne kompaktowymi indeksami
całkowitymi w tablicy account_keys wiadomości.
Przykład: instrukcja transferu SOL
Poniższy przykład pokazuje strukturę instrukcji transferu SOL.
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));
Poniższy kod pokazuje wynik wcześniejszych fragmentów kodu. Format będzie się
różnić w zależności od SDK, ale zwróć uwagę, że każda instrukcja zawiera te same
trzy wymagane elementy: 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}}
Poniższe przykłady pokazują, jak ręcznie zbudować instrukcję transferu.
(Zakładka Expanded Instruction jest funkcjonalnie równoważna zakładce
Instruction.)
W praktyce zazwyczaj nie musisz ręcznie konstruować Instruction.
Większość programów udostępnia biblioteki klienckie z funkcjami pomocniczymi,
które tworzą instrukcje za Ciebie. Jeśli biblioteka nie jest dostępna, możesz
zbudować instrukcję ręcznie.
const transferAmount = 0.01; // 0.01 SOLconst transferInstruction = getTransferSolInstruction({source: sender,destination: recipient.address,amount: transferAmount * LAMPORTS_PER_SOL});
Is this page helpful?