Instrukcje
Instrukcje są podstawowym elementem interakcji z blockchainem Solana. Instrukcja to w zasadzie publiczna funkcja, którą może wywołać każdy użytkownik sieci Solana. Każda instrukcja służy do wykonania określonej akcji. Logika wykonania instrukcji jest przechowywana w programach, gdzie każdy program definiuje swój własny zestaw instrukcji. Aby wejść w interakcję z siecią Solana, jedna lub więcej instrukcji jest dodawana do transakcji i wysyłana do sieci w celu przetworzenia.
Przykład transferu SOL
Poniższy diagram pokazuje, jak transakcje i instrukcje współpracują, aby umożliwić użytkownikom interakcję z siecią. W tym przykładzie SOL jest przesyłany z jednego konta na drugie.
Metadane konta nadawcy wskazują, że musi ono podpisać transakcję. (Pozwala to Programowi Systemowemu odjąć lamporty.) Zarówno konto nadawcy, jak i odbiorcy muszą być zapisywalne, aby ich saldo lamportów mogło się zmienić. Aby wykonać tę instrukcję, portfel nadawcy wysyła transakcję zawierającą jego podpis oraz wiadomość zawierającą instrukcję transferu SOL.
Diagram transferu SOL
Po wysłaniu transakcji Program Systemowy przetwarza instrukcję transferu i aktualizuje saldo lamportów obu kont.
Diagram procesu transferu SOL
Poniższy przykład pokazuje kod związany z powyższymi diagramami. (Zobacz instrukcję transferu Programu Systemowego tutaj.)
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 clusterconst rpc = createSolanaRpc("http://localhost:8899");const rpcSubscriptions = createSolanaRpcSubscriptions("ws://localhost:8900");// Generate sender and recipient keypairsconst 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 airdropawait airdropFactory({ rpc, rpcSubscriptions })({recipientAddress: sender.address,lamports: lamports(LAMPORTS_PER_SOL), // 1 SOLcommitment: "confirmed"});// Check balance before transferconst { 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 recipientconst transferInstruction = getTransferSolInstruction({source: sender,destination: recipient.address,amount: transferAmount // 0.01 SOL in lamports});// Add the transfer instruction to a new transactionconst { 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 networkconst signedTransaction =await signTransactionMessageWithSigners(transactionMessage);await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })(signedTransaction,{ commitment: "confirmed" });const transactionSignature = getSignatureFromTransaction(signedTransaction);// Check balance after transferconst { 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.
Instrukcje
Diagram przedstawiający transakcję z instrukcją, podzieloną na 3 komponenty
Instrukcja
Instruction
składa się z następujących informacji:
program_id
: ID programu, który jest wywoływany.accounts
: Tablica metadanych kontadata
: Tablica bajtów zawierająca dodatkowe [dane], które są używane przez instrukcję.
Instruction struct
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>,}
ID programu
program_id
instrukcji to adres
klucza publicznego programu, który zawiera logikę biznesową instrukcji.
Metadane konta
Tablica accounts
instrukcji to tablica struktur
AccountMeta
.
Metadane muszą być dostarczone dla każdego konta, z którym instrukcja wchodzi w
interakcję. (Pozwala to na wykonywanie instrukcji w ramach transakcji
równolegle, o ile nie modyfikują tego samego konta.)
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.
Metadane konta zawierają następujące informacje:
- pubkey: Adres klucza publicznego 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ę, które konta są wymagane przez instrukcję, w tym które muszą być zapisywalne, tylko do odczytu lub podpisać transakcję, należy odnieść się do implementacji instrukcji, zdefiniowanej przez program.
AccountMeta
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
data
instrukcji to tablica bajtów, która określa, którą instrukcję programu
należy wywołać. Zawiera również wszelkie argumenty wymagane przez instrukcję.
Przykład tworzenia instrukcji
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));
Console
Click to execute the code.
Kod poniżej pokazuje wynik z poprzednich fragmentów kodu. Format będzie się
różnił w zależności od SDK, ale zauważ, ż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 tworzyć Instruction
. Większość
programów dostarcza biblioteki klienckie z funkcjami pomocniczymi, które
tworzą instrukcje za Ciebie. Jeśli biblioteka nie jest dostępna, możesz
ręcznie zbudować instrukcję.
const transferAmount = 0.01; // 0.01 SOLconst transferInstruction = getTransferSolInstruction({source: sender,destination: recipient.address,amount: transferAmount * LAMPORTS_PER_SOL});
Is this page helpful?