導入
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を使う場面を見ていきます。