신규: Helius가 Light Protocol을 인수했습니다
Solana에서 계정 데이터를 역직렬화하는 방법
블로그/개발

Solana 개발 101 - Solana 계정 데이터 역직렬화

개발자 관계 책임자LinkedIn의 Hunter Davis
읽는 데 5분

소개

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 계정 데이터를 역직렬화하는 데 필요한 원시 민트 형식과 레이아웃이 정의됩니다.

이제 위와 비슷하게 인터페이스와 레이아웃을 설정할 수 있습니다.

코드
// 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 파일로 가져와 앞서 반환된 데이터를 역직렬화할 수 있습니다.

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 개발 소식을 확인하고 새 게시물 알림을 받아보세요

확대 이미지