反序列化 Solana 上的帐户数据

在本教程中,我们将介绍如何从令牌帐户反序列化帐户数据,并返回您可以使用的可读数据。您将使用一个简单的示例,使用代币程序库从 NFT 的铸币地址中分解原始帐户信息。

反序列化 Solana 上的帐户数据
Solana Dev 101 - 反序列化 Solana 上的帐户数据

介绍

与 Solana 上的数据交互可能具有挑战性。帐户和交易数据通常会被编码,这有利于提高效率,但不利于开发人员的理智。 Solana 使用Borsh(用于散列的二进制对象表示序列化器)进行数据序列化,其中包括序列化和反序列化过程。 Borsh 的主要优势之一是它的确定性,确保相同输入的一致的序列化输出。

在本教程中,我们将介绍如何从令牌帐户反序列化帐户数据,并返回您可以使用的可读数据。您将使用一个简单的示例,使用代币程序库从 NFT 的铸币地址中分解原始帐户信息。

下面介绍了我们如何将原始帐户数据转换为更具可读性的数据:

您可以通过克隆我们的 deserialize-account 存储库(此处)来遵循本教程中的完整代码。

先决条件

以下是本教程的先决条件:

环境设置

  1. 克隆示例存储库:

git clone https://github.com/helius-labs/deserialize-base.git

  1. 导航到项目目录:

cd deserialize-base

  1. 安装 npm:

npm install

现在您已经完成了项目设置!现在,您可以开始构建如何反序列化给定铸币地址的帐户数据。

构建步骤

1. 获取账户数据

  1. 在我们的 /src/deserialize.ts 文件中,让我们导入所需的模块:

import { Connection, PublicKey } from "@solana/web3.js";

稍后您将使用它来定义与 Solana 的连接,以及您想要反序列化数据的 Mint 的 PublicKey。

  1. 在此之下,您将设置主要功能。您还将使用 Helius RPC URL 设置 Solana 连接,并且可以设置将在教程中反序列化的 mint。

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 密钥。您也可以将本教程中使用的薄荷替换为您自己的示例。

  1. 接下来,您将设置一个 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 mint 6MWfAt3S9Xu4ybxxgPm6e4LSwuXfyAwGXd5yfUqpox9K 的 AccountInfo。为此,您必须分解Solana 程序库中提供给我们的原始薄荷数据的类型和缓冲区布局。了解给定数据的结构是反序列化 Solana 上任何数据的关键步骤。

上面为您提供了定义 RawMint 结构和 MintLayout 的程序。实际上,您只需将它们复制到我们的类型文件中即可使用。现在,转到我们的 ./src/types 目录。

  1. 现在,在 /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 帐户数据所需的上述原始 Mint 格式和布局。

  1. 您现在可以设置与上面类似的界面和布局,请注意,您正在使用我们导入的 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 文件进行设置。

  1. 首先,在我们的主 deserialize.ts 文件中,从 types.ts 文件导入 MintLayout:

import { MintLayout } from "./types";

  1. 现在,您只需在我们的反序列化函数中添加一行,就在您获取帐户数据的位置下方:

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


这绝对更具可读性!您可以通过将下一步中的响应分解为响应中的类型来使此操作更加简洁。

  1. 最后,您仍然可以通过调整上面显示的响应来清理这些数据。您可以通过执行以下操作来实现此目的:

// 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 格式返回的 PublicKey 转换。否则,数据可以按照接收到的格式返回。由于数据格式是预期的,我们也可以提前设置。

这将返回以下内容:


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 账户数据!您可以将相同的方法应用于其他用例,并使用类似的研究方法来找出给定数据的程序结构。

请务必检查要反序列化数据的程序的源,并尝试匹配这些方法来自行完成此操作。

💡
原文链接:Solana Dev 101 - Deserializing Account Data on Solana
本文由SlerfTools翻译,转载请注明出处。

SlerfTools专为Solana设计的工具箱,致力于简化区块链操作,提供无编程全可视化界面,使发币管理流动性无代码创建Dapp等复杂过程变得安全简单。