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


