本文へスキップ
BecomeCoder

Solanaコース · 第7章 Anchorフレームワーク · レッスン28

#[account] データ構造と IDL

ローカル実施

導入

Anchorでオンチェーンの状態(保存するデータ)を定義するときに使うのが #[account] マクロです。そしてプログラムをビルドすると、自動で IDL というファイルが生成されます。この2つが、Rustのプログラムと、TypeScriptで書くクライアント(第9章)をつなぐ橋渡しになります。

説明

#[account] を付けた構造体は、オンチェーンに保存できる「状態の型」になります。

#[account]
pub struct GreetingAccount {
    pub message: String,   // 4バイト(長さ) + 文字数分
    pub owner: Pubkey,      // 32バイト
    pub count: u64,          // 8バイト
}

#[account] が付いた型には、Anchorが自動で先頭8バイトの**ディスクリミネータ(discriminator)**を付与します。これは「このデータがどの型か」を識別するための署名のようなもので、間違った型として読み込もうとするデシリアライズを防ぎます。space を見積もるときは、このディスクリミネータ分を忘れずに足します。

space = 8(ディスクリミネータ) + 4 + 200(message: 可変長文字列の目安) + 32(owner: Pubkey) + 8(count: u64)

そして anchor build を実行すると、プログラムの命令・アカウント・型の情報をまとめた IDL(Interface Description Language) というJSONファイルが target/idl/ に自動生成されます。

flowchart LR
    R["lib.rs<br/>#[program] / #[derive(Accounts)] / #[account]"] -- "anchor build" --> IDL["IDL(JSON)<br/>命令名・引数の型・アカウント一覧"]
    IDL -- 型定義として利用 --> TS["TypeScriptクライアント<br/>program.methods.initialize(...)"]
    IDL -- 型定義として利用 --> Test["テストコード(第9章)"]

IDLがあることで、クライアント側は「このプログラムにはどんな命令があり、それぞれ何のアカウントと引数が必要か」を自動生成された型として扱えます。Rustの構造体を1つ書き換えれば、ビルドし直すだけでクライアント側の型も追従する――これがAnchorが「フルスタックのフレームワーク」と呼ばれる理由です。

演習

もしIDLという仕組みがなく、Rust側の命令の引数の順序をクライアント(TypeScript)側が手打ちで合わせなければならないとしたら、どんなバグが起きやすくなるか考えてみましょう。

ヒント1を見る

Rust側で引数の順序を1つ入れ替えたのに、クライアント側を直し忘れる、というケースを想像してください。

ヒント2を見る

IDLは「型で同期を保証する」仕組みです。第9章のクライアントコードで実際にIDLを使う場面を見ていきます。