指令

指令是与 Solana 区块链交互的基本构建块。指令本质上是一个公共函数,任何使用 Solana 网络的人都可以调用。每个指令用于执行特定的操作。指令的执行逻辑存储在程序中,每个程序定义其自己的指令集。要与 Solana 网络交互,需要将一个或多个指令添加到交易中并发送到网络进行处理。

SOL 转账示例

下图展示了交易和指令如何协同工作,使用户能够与网络交互。在此示例中,SOL 从一个账户转移到另一个账户。

发送方账户的元数据表明它必须为交易签名。(这允许系统程序扣除lamports。)发送方和接收方账户都必须是可写的,以便其 lamport 余额发生变化。为了执行此指令,发送方的钱包发送包含其签名和包含 SOL 转账指令的消息的交易。

SOL 转账图示SOL 转账图示

交易发送后,系统程序处理转账指令并更新两个账户的 lamport 余额。

SOL 转账处理图示SOL 转账处理图示

下面的示例展示了与上述图示相关的代码。(请参阅系统程序的转账指令。)

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 cluster
const rpc = createSolanaRpc("http://localhost:8899");
const rpcSubscriptions = createSolanaRpcSubscriptions("ws://localhost:8900");
// Generate sender and recipient keypairs
const 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 airdrop
await airdropFactory({ rpc, rpcSubscriptions })({
recipientAddress: sender.address,
lamports: lamports(LAMPORTS_PER_SOL), // 1 SOL
commitment: "confirmed"
});
// Check balance before transfer
const { 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 recipient
const transferInstruction = getTransferSolInstruction({
source: sender,
destination: recipient.address,
amount: transferAmount // 0.01 SOL in lamports
});
// Add the transfer instruction to a new transaction
const { 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 network
const signedTransaction =
await signTransactionMessageWithSigners(transactionMessage);
await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })(
signedTransaction,
{ commitment: "confirmed" }
);
const transactionSignature = getSignatureFromTransaction(signedTransaction);
// Check balance after transfer
const { 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.

指令

展示包含指令的交易及其三个组成部分的图示展示包含指令的交易及其三个组成部分的图示

一个 Instruction 包含以下信息:

  • program_id:被调用程序的ID
  • accounts:一个 账户元数据的数组。
  • data:一个包含指令所需额外[数据]的字节数组。
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

指令的program_id是包含指令业务逻辑的程序的公钥地址。

账户元数据

指令的 accounts 数组是一个 AccountMeta 结构体的数组。每个指令交互的账户都必须提供元数据。(这允许交易并行执行指令,只要它们不修改同一个账户。)

下图展示了一个包含单个指令的交易。指令的 accounts 数组包含两个账户的元数据。

一个包含一个指令的交易。指令包含两个 AccountMeta 结构体在其 accounts 数组中。一个包含一个指令的交易。指令包含两个 AccountMeta 结构体在其 accounts 数组中。

账户元数据包括以下信息:

  • pubkey:账户的公钥地址
  • is_signer:如果账户必须签署交易,则设置为 true
  • is_writable:如果指令修改账户的数据,则设置为 true

要了解指令需要哪些账户,包括哪些必须是可写、只读或签署交易的账户,您必须参考程序定义的指令实现。

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,
}

数据

指令的 data 是一个字节数组,用于指定调用程序的哪条指令。它还包括指令所需的任何参数。

创建指令示例

下面的示例展示了一个 SOL 转账指令的结构。

import { generateKeyPairSigner, lamports } from "@solana/kit";
import { getTransferSolInstruction } from "@solana-program/system";
// Generate sender and recipient keypairs
const sender = await generateKeyPairSigner();
const recipient = await generateKeyPairSigner();
// Define the amount to transfer
const 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 recipient
const transferInstruction = getTransferSolInstruction({
source: sender,
destination: recipient.address,
amount: transferAmount
});
console.log(JSON.stringify(transferInstruction, null, 2));
Console
Click to execute the code.

以下代码显示了前面代码片段的输出。格式会因 SDK 而异,但请注意,每个指令都包含相同的三条必要信息:program_idaccountsdata

{
"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
}
}

以下示例展示了如何手动构建转账指令。(Expanded Instruction 标签与 Instruction 标签在功能上是等效的。)

实际操作中,通常不需要手动构建 Instruction。 大多数程序提供了带有辅助函数的客户端库,这些函数会为您创建指令。如果没有可用的库,您可以手动构建指令。

const transferAmount = 0.01; // 0.01 SOL
const transferInstruction = getTransferSolInstruction({
source: sender,
destination: recipient.address,
amount: transferAmount * LAMPORTS_PER_SOL
});

Is this page helpful?

Table of Contents

Edit Page

管理者

©️ 2025 Solana 基金会版权所有
取得联系
指令 | Solana