
Solana 开发入门 101:反序列化 Solana 账户数据
简介
与 Solana 上的数据交互可能颇具挑战。账户和交易数据通常经过编码,这有利于提升效率,却会让开发者难以理解。
Solana 使用 Borsh(Binary Object Representation Serializer for Hashing)进行数据序列化,其中包括序列化和反序列化过程。Borsh 的主要优势之一是确定性,可确保相同输入始终产生一致的序列化输出。
本教程将介绍如何反序列化代币账户中的账户数据,并返回可供使用的可读数据。你将通过一个简单示例,使用 Token Program 库,根据 NFT 的铸造地址解析其原始账户信息。
下面展示了如何将原始账户数据转换为更易读的形式:
你可以克隆我们的 deserialize-account 仓库,在这里查看并跟随本教程的完整代码。
前提条件
本教程需要满足以下前提条件:
环境设置
克隆示例仓库:
git clone https://github.com/helius-labs/deserialize-base.git进入项目目录:
cd deserialize-base安装 npm:
npm install现在项目已经设置完成!
接下来,你可以开始构建针对给定铸造地址的账户数据反序列化逻辑。
构建步骤
请按照以下步骤操作:
1. 获取账户数据
在我们的 /src/deserialize.ts 文件中,导入所需模块:
import { Connection, PublicKey } from "@solana/web3.js";稍后,你将使用这些模块定义与 Solana 的连接,以及要反序列化其数据的铸造地址 PublicKey。
在这段代码下方设置主函数。
你还将使用 Helius RPC URL 设置 Solana 连接,并指定本教程中要反序列化的铸造地址。
async function deserializeMint() {
// CONNECTION TO SOLANA USING HELIUS
const rpc = 'https://rpc.helius.xyz/?api-key=';
const connection = new Connection(rpc);
// MINT THAT WE ARE DESERIALIZING
const mint = new PublicKey('6MWfAt3S9Xu4ybxxgPm6e4LSwuXfyAwGXd5yfUqpox9K');
}
deserializeMint()请务必将上面的 api-key 替换为你自己的 Helius API 密钥。你也可以将其中的铸造地址替换为自己的示例。
接下来,设置 try/catch 来获取该铸造地址的原始账户数据:
try {
let { data } = (await connection.getAccountInfo(mint)) || {};
if (!data) {
return;
}
console.log(data);
} catch {
return null;
}在上面的步骤中,你通过已建立的连接在 Solana 上为 getAccountInfo 发起 RPC 调用。这将返回需要进一步解析的初始数据。
如果未找到数据,它将返回 null。否则,搜索结果将输出到终端。
现在可以运行 ts-node deserialize 查看结果。
你应该会看到类似以下内容的结果:
这里进行反序列化的目的是将数据转换为可读格式。
为此,开发者需要查看相关源代码,找到创建该数据的程序所规定的数据布局。
2. 设置账户类型
在本例中,你需要获取 SPL 铸造地址 6MWfAt3S9Xu4ybxxgPm6e4LSwuXfyAwGXd5yfUqpox9K 的 AccountInfo。
为此,你需要解析 Solana Program Library 中提供的原始铸造数据类型和缓冲区布局。理解给定数据的结构,是反序列化 Solana 上任何数据的关键一步。
上图展示了程序定义的 RawMint 结构体和 MintLayout。你可以直接将它们复制到类型文件中使用。
现在,进入 ./src/types 目录。
在 /src/types.ts 文件中,为类型设置导入:
import { PublicKey } from "@solana/web3.js";
import { u32, u8, struct } from "@solana/buffer-layout";
import { publicKey, u64, bool } from "@solana/buffer-layout-utils";这将定义反序列化本例中 NFT 账户数据所需的原始铸造数据格式和布局。
现在,你可以参照上面的内容设置接口和布局。
这里使用的是我们导入的 PublicKey、u32、u8、publicKey、u64 和 bool。
// Defining RawMint from https://github.com/solana-labs/solana-program-library/blob/48fbb5b7c49ea35848442bba470b89331dea2b2b/token/js/src/state/mint.ts#L31 //
export interface RawMint {
mintAuthorityOption: 1 | 0;
mintAuthority: PublicKey;
supply: bigint;
decimals: number;
isInitialized: boolean;
freezeAuthorityOption: 1 | 0;
freezeAuthority: PublicKey;
}
// Defining Buffer Layout from https://github.com/solana-labs/solana-program-library/blob/48fbb5b7c49ea35848442bba470b89331dea2b2b/token/js/src/state/mint.ts#L31 //
/** Buffer layout for de/serializing a mint */
export const MintLayout = struct([
u32('mintAuthorityOption'),
publicKey('mintAuthority'),
u64('supply'),
u8('decimals'),
bool('isInitialized'),
u32('freezeAuthorityOption'),
publicKey('freezeAuthority'),
]);现在,你已经为原始账户信息设置好了类型!接下来,可以在主 deserialize.ts 文件中导入这些类型,并用它们反序列化之前返回的数据。
在 MintLayout 中,RawMint 被定义为结构体。实际上,这就是让你设置的接口使用 GitHub 源代码中定义的布局类型。
3. 反序列化返回的数据
了解预期数据的结构后,你就可以设置解码函数,它只需要一行代码。返回 src/deserialize.ts 文件进行设置。
首先,在主 deserialize.ts 文件中,从 types.ts 文件导入 MintLayout:
import { MintLayout } from "./types";现在,只需在获取账户数据的代码下方,向反序列化函数添加一行代码:
const deserialize = MintLayout.decode(data)
console.log(deserialize)这会使用 MintLayout 解码 deserializeMint 函数返回的数据。
你可以在 ./src 文件夹中运行 ts-node deserialize,并获得类似以下内容的结果:
{
mintAuthorityOption: 1,
mintAuthority: PublicKey [PublicKey(5WQAPQ8i8wqHcSWSEkBQ9kqfwRJxxgyZqAtKiwJSW5zT)] {
_bn:
},
supply: 1n,
decimals: 0,
isInitialized: true,
freezeAuthorityOption: 1,
freezeAuthority: PublicKey [PublicKey(5WQAPQ8i8wqHcSWSEkBQ9kqfwRJxxgyZqAtKiwJSW5zT)] {
_bn:
}
}这显然更易读了!下一步可以根据响应中的类型进一步解析响应,让结果更整洁。
最后,你仍然可以调整响应,将这些数据整理成上面显示的格式。具体操作如下:
// Breaking down the response //
console.log(deserialize.mintAuthorityOption)
console.log(deserialize.mintAuthority.toString())
console.log(deserialize.decimals)
console.log(deserialize.isInitialized)
console.log(deserialize.freezeAuthorityOption)
console.log(deserialize.freezeAuthority.toString())在上面的代码中,只需转换以 toString 格式返回的 PublicKeys。其他数据可以保持接收时的格式返回。由于数据格式是确定的,我们也可以预先完成此设置,这将返回以下内容:
1
5WQAPQ8i8wqHcSWSEkBQ9kqfwRJxxgyZqAtKiwJSW5zT
0
true
1你可以按需要调整这些数据。
这只是将数据解析成更方便查看结果的形式。
完整代码:
在这里查看 deserialize.ts 的完整代码:
import { Connection, PublicKey } from "@solana/web3.js";
import { RawMint, MintLayout } from "./types";
async function deserializeMint() {
const rpc =
"https://rpc.helius.xyz/?api-key=";
const connection = new Connection(rpc);
const mint = new PublicKey("6MWfAt3S9Xu4ybxxgPm6e4LSwuXfyAwGXd5yfUqpox9K");
try {
let { data } = (await connection.getAccountInfo(mint)) || {};
if (!data) {
return;
}
// Data returned.
console.log(data);
// Deserialize Data.
const deserialize = MintLayout.decode(data)
// Breaking down the response //
console.log(deserialize.mintAuthorityOption)
console.log(deserialize.mintAuthority.toString())
console.log(deserialize.decimals)
console.log(deserialize.isInitialized)
console.log(deserialize.freezeAuthorityOption)
console.log(deserialize.freezeAuthority.toString)
} catch {
return null;
}
}
deserializeMint();总结
现在,你已经成功反序列化了 Solana 上的 NFT 账户数据!你可以将同样的方法应用到其他用例中,并使用类似的研究方法确定给定数据所属程序的结构。
请务必查看你要反序列化其数据的程序源代码,并尝试使用这些方法自行完成反序列化。
资源
相关文章
订阅 Helius
及时了解 Solana 开发的最新动态,并在我们发布新内容时收到更新


