Tóm tắt
Một instruction có 3 trường: program_id (program nào sẽ được gọi),
accounts (danh sách AccountMeta với các cờ is_signer/is_writable), và data
(mảng byte dữ liệu mà program sẽ diễn giải).
Cấu trúc instruction
Một
Instruction
bao gồm ba trường:
program_id: ID của program đang được gọi.accounts: Một mảng metadata của accountdata: Một mảng byte với dữ liệu bổ sung để instruction sử dụng.
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 của instruction là địa
chỉ public key của program chứa logic thực thi của instruction. Runtime sử dụng
trường này để định tuyến instruction đến đúng program để xử lý.
Metadata của account
Mảng accounts của instruction là một danh sách có thứ tự các struct
AccountMeta.
Metadata phải được cung cấp cho mỗi account mà instruction tương tác. Validator
sử dụng metadata này để xác định transaction nào có thể chạy song song. Các
transaction ghi vào các account khác nhau có thể thực thi song song.
Sơ đồ dưới đây mô tả một transaction chứa một instruction duy nhất. Mảng
accounts của instruction chứa metadata cho hai account.
Một transaction với một instruction. Instruction chứa hai struct AccountMeta trong mảng accounts của nó.
Mỗi AccountMeta có ba trường:
- pubkey: Địa chỉ public key của account
- is_signer: Đặt thành
truenếu account phải ký transaction - is_writable: Đặt thành
truenếu instruction sửa đổi dữ liệu của account
Để biết instruction yêu cầu những tài khoản nào, bao gồm tài khoản nào phải có khả năng ghi, chỉ đọc, hoặc ký giao dịch, bạn phải tham khảo cách triển khai của instruction, như được định nghĩa bởi chương trình.
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,}
Dữ liệu
Trường data của instruction là một mảng byte cho chương trình biết hàm nào cần
gọi và cung cấp các đối số cho hàm đó. Dữ liệu thường bắt đầu bằng discriminator
hoặc (các) byte chỉ mục xác định hàm đích, theo sau là các đối số đã được
serialize. Định dạng mã hóa được định nghĩa bởi từng chương trình (ví dụ: Borsh
serialization hoặc layout tùy chỉnh).
Các quy ước mã hóa phổ biến:
- Chương trình lõi (System, Stake, Vote): Sử dụng chỉ mục biến thể enum được serialize bằng Bincode, theo sau là các đối số đã serialize.
- Chương trình Anchor: Sử dụng discriminator 8 byte (8 byte đầu tiên của
hash SHA-256 của
"global:<function_name>"), theo sau là các đối số được serialize bằng Borsh.
Runtime không diễn giải trường data. Nó được truyền nguyên trạng đến
entrypoint process_instruction của chương trình.
Compiled instruction
Khi các instruction được serialize thành transaction message, chúng trở thành
các struct
CompiledInstruction
thay thế tất cả public key bằng các chỉ mục số nguyên nhỏ gọn trong mảng
account_keys của message.
Ví dụ: instruction chuyển SOL
Ví dụ dưới đây cho thấy cấu trúc của một instruction chuyển 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));
Đoạn code dưới đây cho thấy kết quả đầu ra từ các đoạn code trước. Định dạng sẽ
khác nhau giữa các SDK, nhưng lưu ý rằng mỗi instruction đều chứa ba thông tin
bắt buộc giống nhau: 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}}
Các ví dụ dưới đây cho thấy cách xây dựng thủ công instruction chuyển token.
(Tab Expanded Instruction về mặt chức năng tương đương với tab Instruction.)
Trong thực tế, bạn thường không cần phải xây dựng Instruction một cách
thủ công. Hầu hết các chương trình đều cung cấp thư viện client với các hàm hỗ
trợ tạo instruction cho bạn. Nếu không có thư viện, bạn có thể xây dựng
instruction theo cách thủ công.
const transferAmount = 0.01; // 0.01 SOLconst transferInstruction = getTransferSolInstruction({source: sender,destination: recipient.address,amount: transferAmount * LAMPORTS_PER_SOL});
Is this page helpful?