账户类型

摘要

program account 存储可执行的 sBPF 代码。数据账户用于存储状态,由程序拥有。系统账户由 System Program 拥有。sysvar 在预定义地址提供集群范围的状态。

executable 字段决定了账户的类别:

  • program accountexecutable = true。包含可执行代码。
  • 数据账户executable = false。用于存储状态或用户数据。

代码与可变状态的分离意味着程序只需部署一次,即可管理任意数量的数据账户。

program account

program account 用于存储可执行代码。每个 program account 都由 loader program 拥有。当 program 部署时,运行时会创建一个 program account 来存放其字节码。

program account 及其 4 个组成部分和 loader program 的示意图program account 及其 4 个组成部分和 loader program 的示意图

程序数据账户

使用 loader-v3 部署的程序(参见 Loader programs)不会将可执行字节码存储在自己的 data 字段中,而是将其 data 指向一个单独的 program data account,该账户包含程序代码。(见下图。)

带有数据的 program account。数据指向一个单独的 program data account带有数据的 program account。数据指向一个单独的 program data account

在程序部署或升级期间,缓冲账户用于临时存储上传内容。

以下示例获取了 Token Program account。executable 字段为 true,确认其为 program account。

import { Address, createSolanaRpc } from "@solana/kit";
const rpc = createSolanaRpc("https://api.mainnet.solana.com");
const programId = "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" as Address;
const accountInfo = await rpc
.getAccountInfo(programId, { encoding: "base64" })
.send();
console.log(accountInfo);
Console
Click to execute the code.

数据账户

数据账户不包含可执行代码,而是用于存储程序自定义的状态。

程序状态账户

程序会将其状态存储在数据账户中。创建程序状态账户需要两个步骤:

  1. 调用 System Program 创建账户。System Program 会将账户所有权转移给指定的程序。
  2. 拥有该账户的程序根据其 instructions 初始化账户的 data 字段。

由 program account 拥有的数据账户示意图由 program account 拥有的数据账户示意图

以下示例演示如何创建并获取由 Token 2022 program 拥有的 Token Mint account。

import {
airdropFactory,
appendTransactionMessageInstructions,
createSolanaRpc,
createSolanaRpcSubscriptions,
createTransactionMessage,
generateKeyPairSigner,
getSignatureFromTransaction,
lamports,
pipe,
sendAndConfirmTransactionFactory,
setTransactionMessageFeePayerSigner,
setTransactionMessageLifetimeUsingBlockhash,
signTransactionMessageWithSigners
} from "@solana/kit";
import { getCreateAccountInstruction } from "@solana-program/system";
import {
getInitializeMintInstruction,
getMintSize,
TOKEN_2022_PROGRAM_ADDRESS,
fetchMint
} from "@solana-program/token-2022";
// Create Connection, local validator in this example
const rpc = createSolanaRpc("http://localhost:8899");
const rpcSubscriptions = createSolanaRpcSubscriptions("ws://localhost:8900");
// Generate keypairs for fee payer
const feePayer = await generateKeyPairSigner();
// Fund fee payer
await airdropFactory({ rpc, rpcSubscriptions })({
recipientAddress: feePayer.address,
lamports: lamports(1_000_000_000n),
commitment: "confirmed"
});
// Generate keypair to use as address of mint
const mint = await generateKeyPairSigner();
// Get default mint account size (in bytes), no extensions enabled
const space = BigInt(getMintSize());
// Get minimum balance for rent exemption
const rent = await rpc.getMinimumBalanceForRentExemption(space).send();
// Instruction to create new account for mint (token 2022 program)
// Invokes the system program
const createAccountInstruction = getCreateAccountInstruction({
payer: feePayer,
newAccount: mint,
lamports: rent,
space,
programAddress: TOKEN_2022_PROGRAM_ADDRESS
});
// Instruction to initialize mint account data
// Invokes the token 2022 program
const initializeMintInstruction = getInitializeMintInstruction({
mint: mint.address,
decimals: 9,
mintAuthority: feePayer.address
});
const instructions = [createAccountInstruction, initializeMintInstruction];
// Get latest blockhash to include in transaction
const { value: latestBlockhash } = await rpc.getLatestBlockhash().send();
// Create transaction message
const transactionMessage = pipe(
createTransactionMessage({ version: 0 }), // Create transaction message
(tx) => setTransactionMessageFeePayerSigner(feePayer, tx), // Set fee payer
(tx) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx), // Set transaction blockhash
(tx) => appendTransactionMessageInstructions(instructions, tx) // Append instructions
);
// Sign transaction message with required signers (fee payer and mint keypair)
const signedTransaction =
await signTransactionMessageWithSigners(transactionMessage);
// Send and confirm transaction
await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })(
signedTransaction,
{ commitment: "confirmed" }
);
// Get transaction signature
const transactionSignature = getSignatureFromTransaction(signedTransaction);
console.log("Mint Address:", mint.address);
console.log("Transaction Signature:", transactionSignature);
const accountInfo = await rpc.getAccountInfo(mint.address).send();
console.log(accountInfo);
const mintAccount = await fetchMint(rpc, mint.address);
console.log(mintAccount);
Console
Click to execute the code.

System accounts

创建后仍由 System Program 拥有的账户称为 system account。首次向新地址发送 SOL 时,会在该地址创建一个由 System Program 拥有的新账户。

所有钱包账户都是 system account。交易的手续费支付者必须是 system account,因为只有 System Program 拥有的账户才能支付 交易手续费

由 System Program 拥有、包含 1,000,000 lamports 的钱包示意图由 System Program 拥有、包含 1,000,000 lamports 的钱包示意图

以下示例生成一个新的 keypair,为其充值 SOL,并获取该账户。owner 字段为 11111111111111111111111111111111System Program)。

import {
airdropFactory,
createSolanaRpc,
createSolanaRpcSubscriptions,
generateKeyPairSigner,
lamports
} from "@solana/kit";
// Create a connection to Solana cluster
const rpc = createSolanaRpc("http://localhost:8899");
const rpcSubscriptions = createSolanaRpcSubscriptions("ws://localhost:8900");
// Generate a new keypair
const keypair = await generateKeyPairSigner();
console.log(`Public Key: ${keypair.address}`);
// Funding an address with SOL automatically creates an account
const signature = await airdropFactory({ rpc, rpcSubscriptions })({
recipientAddress: keypair.address,
lamports: lamports(1_000_000_000n),
commitment: "confirmed"
});
const accountInfo = await rpc.getAccountInfo(keypair.address).send();
console.log(accountInfo);
Console
Click to execute the code.

Sysvar 账户

Sysvar 账户 是在预定义地址上的特殊账户,提供对集群状态数据的只读访问。它们会在每个 slot 动态更新。

SysvarAddressPurpose
ClockSysvarC1ock11111111111111111111111111111111当前 slot、epoch 和 Unix 时间戳
EpochScheduleSysvarEpochSchedu1e111111111111111111111111在创世块中设定的 epoch 调度常量
EpochRewardsSysvarEpochRewards1111111111111111111111111epoch 奖励分配状态与进度
RentSysvarRent111111111111111111111111111111111租金费率与免租门槛
SlotHashesSysvarS1otHashes111111111111111111111111111slot 父银行的最新哈希值
StakeHistorySysvarStakeHistory1111111111111111111111111每个 epoch 的质押激活与撤销记录
LastRestartSlotSysvarLastRestartS1ot1111111111111111111111上一次集群重启的 slot
InstructionsSysvar1nstructions1111111111111111111111111当前交易的序列化指令
SlotHistorySysvarS1otHistory11111111111111111111111111最近一个 epoch 内已产出的 slot 记录

以下示例演示如何获取并反序列化 Sysvar Clock 账户。

import { createSolanaRpc } from "@solana/kit";
import { fetchSysvarClock, SYSVAR_CLOCK_ADDRESS } from "@solana/sysvars";
const rpc = createSolanaRpc("https://api.mainnet.solana.com");
const accountInfo = await rpc
.getAccountInfo(SYSVAR_CLOCK_ADDRESS, { encoding: "base64" })
.send();
console.log(accountInfo);
// Automatically fetch and deserialize the account data
const clock = await fetchSysvarClock(rpc);
console.log(clock);
Console
Click to execute the code.

Is this page helpful?

Table of Contents

Edit Page

管理者

©️ 2026 Solana 基金会版权所有
取得联系