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);
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 kontdata: Tablica bajtów z dodatkowymi [danymi], które mają być 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>,}
ID programu
program_id instrukcji to adres
public key programu, który zawiera logikę biznesową instrukcji.
Metadane konta
Tablica accounts instrukcji to tablica struktur
AccountMeta.
Metadane muszą być podane dla każdego konta, z którym instrukcja wchodzi w
interakcję. (Pozwala to na wykonywanie instrukcji 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 public key konta
- is_signer: Ustaw na
true, jeśli konto musi podpisać transakcję - is_writable: Ustaw 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.
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 określająca, którą z instrukcji programu
należy wywołać. Zawiera także 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));
Poniższy kod pokazuje wynik wcześniejszych fragmentów kodu. Format może się
różnić w zależności od SDK, ale każda instrukcja zawiera te same trzy wymagane
informacje: 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?