接口定义语言 (IDL) 文件提供了描述程序指令和账户的标准化 JSON 文件。此文件简化了链上程序与客户端应用程序集成的过程。

IDL 的主要优势:

  • 标准化:提供一致的格式来描述程序的指令和帐户
  • 客户端生成:用于生成与程序交互的客户端代码

anchor build命令生成一个位于 的 IDL 文件 /target/idl/<program-name>.json
下面的代码片段突出显示了程序、IDL 和客户端如何相互关联。

程序指令

IDL 中的数组instructions直接对应于程序中定义的指令。它指定每条指令所需的帐户和参数。

  • Program:下面的程序包含一条initialize指令,指定其所需的帐户和参数。
  • 程序帐户:accounts IDL 中的数组对应于程序中用宏注释的结构体。#[account]这些结构体定义了程序创建的账户中存储的数据。
use anchor_lang::prelude::*;

declare_id!("BYFW1vhC1ohxwRbYoLbAWs86STa25i9sD5uEusVjTYNd");

#[program]
mod hello_anchor {
    use super::*;
    pub fn initialize(ctx: Context<Initialize>, data: u64) -> Result<()> {
        ctx.accounts.new_account.data = data;
        msg!("Changed data to: {}!", data);
        Ok(())
    }
}

#[derive(Accounts)]
pub struct Initialize<'info> {
    #[account(init, payer = signer, space = 8 + 8)]
    pub new_account: Account<'info, NewAccount>,
    #[account(mut)]
    pub signer: Signer<'info>,
    pub system_program: Program<'info, System>,
}

#[account]
pub struct NewAccount {
    data: u64,
}

IDL

生成的 IDL 文件包含标准化 JSON 格式的指令,包括其名称、帐户、参数和鉴别器。

{
  "address": "BYFW1vhC1ohxwRbYoLbAWs86STa25i9sD5uEusVjTYNd",
  "metadata": {
    "name": "hello_anchor",
    "version": "0.1.0",
    "spec": "0.1.0",
    "description": "Created with Anchor"
  },
  "instructions": [
    {
      "name": "initialize",
      "discriminator": [175, 175, 109, 31, 13, 152, 155, 237],
      "accounts": [
        {
          "name": "new_account",
          "writable": true,
          "signer": true
        },
        {
          "name": "signer",
          "writable": true,
          "signer": true
        },
        {
          "name": "system_program",
          "address": "11111111111111111111111111111111"
        }
      ],
      "args": [
        {
          "name": "data",
          "type": "u64"
        }
      ]
    }
  ],
  "accounts": [
    {
      "name": "NewAccount",
      "discriminator": [176, 95, 4, 118, 91, 177, 125, 232]
    }
  ],
  "types": [
    {
      "name": "NewAccount",
      "type": {
        "kind": "struct",
        "fields": [
          {
            "name": "data",
            "type": "u64"
          }
        ]
      }
    }
  ]
}

Client

然后使用IDL文件生成与程序交互的客户端,简化调用程序指令的过程。

import * as anchor from "@coral-xyz/anchor";
import { Program, BN } from "@coral-xyz/anchor";
import { HelloAnchor } from "../target/types/hello_anchor";
import { Keypair } from "@solana/web3.js";
import assert from "assert";

describe("hello_anchor", () => {
  const provider = anchor.AnchorProvider.env();
  anchor.setProvider(provider);
  const wallet = provider.wallet as anchor.Wallet;
  const program = anchor.workspace.HelloAnchor as Program<HelloAnchor>;

  it("initialize", async () => {
    // Generate keypair for the new account
    const newAccountKp = new Keypair();

    // Send transaction
    const data = new BN(42);
    const transactionSignature = await program.methods
      .initialize(data)
      .accounts({
        newAccount: newAccountKp.publicKey,
        signer: wallet.publicKey,
      })
      .signers([newAccountKp])
      .rpc();

    // Fetch the created account
    const newAccount = await program.account.newAccount.fetch(
      newAccountKp.publicKey,
    );

    console.log("Transaction signature: ", transactionSignature);
    console.log("On-chain data is:", newAccount.data.toString());
    assert(data.eq(newAccount.data));
  });
});

鉴别器

Anchor 为程序中的每个指令和账户类型分配一个唯一的 8 字节鉴别符。这些鉴别符作为标识符来区分不同的指令或账户类型。
鉴别器是使用前缀的 Sha256 哈希的前 8 个字节与指令或帐户名称相结合生成的。从 Anchor v0.30 开始,这些鉴别器包含在 IDL 文件中。
请注意,使用 Anchor 时,您通常不需要直接与这些鉴别器交互。本节主要介绍如何生成和使用鉴别器。

instructions

指令鉴别器被程序用来决定在调用时要执行哪条具体指令。
当调用 Anchor 程序指令时,鉴别符将作为指令数据的前 8 个字节包含在内。此操作由 Anchor 客户端自动完成。

IDL

  "instructions": [
    {
      "name": "initialize",
      "discriminator": [175, 175, 109, 31, 13, 152, 155, 237],
       ...
    }
  ]

accounts

账户鉴别器用于在反序列化链上数据时识别具体的账户类型,在账户创建时设置。

IDL

  "accounts": [
    {
      "name": "NewAccount",
      "discriminator": [176, 95, 4, 118, 91, 177, 125, 232]
    }
  ]

指令的鉴别器是前缀的 Sha256 哈希的前 8 个字节global加上指令名称。

例如:

sha256("global:initialize")

十六进制输出:

af af 6d 1f 0d 98 9b ed d4 6a 95 07 32 81 ad c2 1b b5 e0 e1 d7 73 b2 fb bd 7a b5 04 cd d4 aa 30

前 8 个字节用作指令的鉴别符。

af = 175
af = 175
6d = 109
1f = 31
0d = 13
98 = 152
9b = 155
ed = 237

您可以在此处的Anchor 代码库中找到鉴别器生成的实现 ,该代码库在此处使用 。

总结:https://solana.com/docs/programs/anchor/idl