从网络读取数据
本节将探讨如何通过获取不同账户来从 Solana 网络读取数据,以了解 Solana 账户的结构。
在 Solana 上,所有数据都存在于“账户”中。可以将 Solana 上的数据视为一个公共数据库,其中只有一个“账户”表,每个条目都是一个具有相同基础 账户类型的账户。
#[derive(PartialEq, Eq, Clone, Default)]pub struct Account {/// lamports in the accountpub lamports: u64,/// data held in this account#[cfg_attr(feature = "serde", serde(with = "serde_bytes"))]pub data: Vec<u8>,/// the program that owns this account. If executable, the program that loads this account.pub owner: Pubkey,/// this account's data contains a loaded program (and is now read-only)pub executable: bool,/// the epoch at which this account will next owe rentpub rent_epoch: Epoch,}
账户
Solana 上的账户可以存储“状态”或“可执行”程序。每个账户都有一个“地址”(公钥),作为其唯一的标识,用于定位其对应的链上数据。
Solana 账户包含以下两种内容之一:
- 状态:用于读取和持久化的数据。例如,关于代币的信息、用户数据或程序中定义的其他数据。
- 可执行程序:包含 Solana 程序实际代码的账户。这些账户存储用户可以调用的指令。
程序代码和程序状态的分离是 Solana 账户模型的一个关键特性。有关更多详细信息,请参阅 Solana 账户模型页面。
获取钱包账户
此示例演示如何:
- 生成一个新的 keypair(公钥/私钥对)。
- 请求一个 SOL 空投以为新地址提供资金。
- 检索已资助地址的账户数据。
在 Solana 上,为新地址提供 SOL 资金会自动创建一个由 System Program 拥有的账户。所有“钱包”账户只是由 System Program 拥有的账户,这些账户持有 SOL 并可以签署交易。
import { Keypair, Connection, LAMPORTS_PER_SOL } from "@solana/web3.js";const keypair = Keypair.generate();console.log(`Public Key: ${keypair.publicKey}`);const connection = new Connection("http://localhost:8899", "confirmed");// Funding an address with SOL automatically creates an accountconst signature = await connection.requestAirdrop(keypair.publicKey,LAMPORTS_PER_SOL);await connection.confirmTransaction(signature, "confirmed");const accountInfo = await connection.getAccountInfo(keypair.publicKey);console.log(JSON.stringify(accountInfo, null, 2));
在 Solana 上,“钱包”是由系统程序拥有的账户,系统程序是 Solana 的内置程序之一。钱包账户主要用于持有 SOL(记录在
lamports
字段中)并签署交易。
当您获取一个钱包账户时,响应中会包含示例输出中显示的字段。
data
字段包含以字节形式存储的账户数据。
对于钱包账户,此字段为空(0 字节)。其他账户使用此字段存储程序状态或可执行程序代码。
executable
字段指示账户的 data
字段是否包含可执行程序代码。
对于钱包和存储程序状态的账户,此字段为 false
。
lamports
字段包含账户的 SOL 余额,以 lamports 为单位。
Lamports 是 SOL 的最小单位。1 SOL = 1,000,000,000 lamports。
owner
字段显示了拥有该账户的程序。
对于钱包账户,所有者始终是 System Program,其地址为
11111111111111111111111111111111
。
rentEpoch
字段是一个遗留字段,源自已弃用的机制,其中账户需要支付 "rent"(以 lamports 为单位)来维护其在网络上的数据。
该字段目前未使用,但为了向后兼容仍然保留。
space
字段显示了 data
字段中的字节数。这不是 Account
类型本身的字段,而是包含在响应中的。
在此示例中,space
字段为 0,因为 data
字段包含 0 字节的数据。
获取 Token Program
此示例获取 Token Program,以演示钱包账户和程序账户之间的区别。
程序账户存储了 Token Program 的编译字节码 源代码。您可以在 Solana Explorer 上查看此程序账户。
import { Connection, PublicKey } from "@solana/web3.js";const connection = new Connection("https://api.mainnet-beta.solana.com","confirmed");const address = new PublicKey("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA");const accountInfo = await connection.getAccountInfo(address);
Token Program 是 Solana 上的一个可执行程序账户。与钱包账户类似,程序账户具有相同的基础 账户 数据结构,但其字段存在关键差异。
{"data": {"type": "Buffer","data": [127, "...truncated, total bytes: 134080...", 0]},"executable": true,"lamports": 4522329612,"owner": "BPFLoader2111111111111111111111111111111111","rentEpoch": 18446744073709552000,"space": 134080}
executable
字段被设置为 true
,表明此账户的 data
字段包含可执行的程序代码。
{"data": {"type": "Buffer","data": [127, "...truncated, total bytes: 134080...", 0]},"executable": true,"lamports": 4522329612,"owner": "BPFLoader2111111111111111111111111111111111","rentEpoch": 18446744073709552000,"space": 134080}
对于程序账户,data
字段存储程序的可执行代码。相比之下,钱包账户的数据字段是空的。
当您部署一个 Solana 程序时,该程序的可执行代码存储在账户的 data
字段中。
{"data": {"type": "Buffer","data": [127, "...truncated, total bytes: 134080...", 0]},"executable": true,"lamports": 4522329612,"owner": "BPFLoader2111111111111111111111111111111111","rentEpoch": 18446744073709552000,"space": 134080}
可执行程序账户还会指定一个程序作为账户的 owner
。
所有程序账户都由一个加载器程序(Loader program)拥有,这是一类内置程序,负责拥有 Solana 上的可执行程序账户。
对于 Token Program,owner
是 BPFLoader2 程序。
{"data": {"type": "Buffer","data": [127, "...truncated, total bytes: 134080...", 0]},"executable": true,"lamports": 4522329612,"owner": "BPFLoader2111111111111111111111111111111111","rentEpoch": 18446744073709552000,"space": 134080}
获取 Mint 账户
此示例获取 USD Coin (USDC) 的 Mint 账户,以展示 Solana 上的程序如何在单独的账户中存储状态。
一个 Mint 账户是由 Token Program 拥有的账户。它存储特定代币的全局元数据,包括总供应量、小数位数,以及被授权铸造或冻结代币的账户。Mint 账户的地址在 Solana 网络上唯一标识一个代币。
import { Connection, PublicKey } from "@solana/web3.js";const connection = new Connection("https://api.mainnet-beta.solana.com","confirmed");const address = new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v");const accountInfo = await connection.getAccountInfo(address);
在此示例中需要注意的关键点是,Mint 账户存储的是状态,而不是可执行代码。
Mint 账户由 Token Program 拥有,该程序包含定义如何创建和更新 Mint 账户的指令。
executable
字段是 false
,因为 Mint 账户的 data
字段存储的是状态,而不是可执行代码。
Token Program 定义了 Mint
数据类型,该类型存储在 Mint 账户的 data
字段中。
data
字段包含序列化的 Mint
账户状态,例如 Mint 权限、总供应量、小数位数。
要从 Mint 账户中读取数据,必须将 data
字段反序列化为 Mint
数据类型。这将在下一步中介绍。
Token Program (TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA
) 拥有 Mint 账户。
这意味着 Mint 账户的 data
字段只能通过 Token Program 定义的指令进行修改。
反序列化 Mint 账户
Solana 账户的 data
字段包含原始字节数据。为了有意义地解释这些数据,必须将其反序列化为拥有该账户的程序定义的适当数据类型。
大多数 Solana 程序提供了带有辅助函数的客户端库,这些函数抽象了反序列化过程。这些函数将原始账户字节数据转换为结构化数据类型,从而更容易处理账户数据。
例如,@solana/spl-token
包含 getMint()
函数,用于帮助将 Mint 账户的 data
字段反序列化为
Mint
数据类型。
import { PublicKey, Connection } from "@solana/web3.js";import { getMint } from "@solana/spl-token";const connection = new Connection("https://api.mainnet-beta.solana.com","confirmed");const address = new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v");const mintData = await getMint(connection, address, "confirmed");
pub struct Mint {/// Optional authority used to mint new tokens. The mint authority may only/// be provided during mint creation. If no mint authority is present/// then the mint has a fixed supply and no further tokens may be/// minted.pub mint_authority: COption<Pubkey>,/// Total supply of tokens.pub supply: u64,/// Number of base 10 digits to the right of the decimal place.pub decimals: u8,/// Is `true` if this structure has been initializedpub is_initialized: bool,/// Optional authority to freeze token accounts.pub freeze_authority: COption<Pubkey>,}
getMint()
函数将 Mint 账户的 data
字段反序列化为由 Token Program 定义的
Mint
数据类型。
{"data": {"type": "Buffer","data": [1, "...truncated, total bytes: 82...", 103]},"executable": false,"lamports": 407438077149,"owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA","rentEpoch": 18446744073709552000,"space": 82}
您可以在 Solana Explorer 上查看完全反序列化的 Mint 账户 数据。
address
字段包含 Mint 账户的地址。
Mint 账户的地址用于标识 Solana 网络上的代币。
mintAuthority
字段显示被授权铸造新代币的权限。
这是唯一可以创建新代币单位的账户。
supply
字段显示已铸造的代币总数。
此值以代币的最小单位表示。要以标准单位获取总供应量,请根据 decimals
调整
supply
字段的值。
decimals
字段显示了该代币的小数位数。
isInitialized
字段指示 Mint 账户是否已初始化。此字段是 Token
Program 中用于安全检查的字段。
freezeAuthority
字段显示了被授权冻结代币账户的权限。
被冻结的代币账户无法转移或销毁账户中的代币。
tlvData
字段包含 Token Extensions 的额外数据(需要进一步反序列化)。
此字段仅与由 Token Extension Program(Token2022)创建的账户相关。
Is this page helpful?