当前位置: 首页 > article >正文

Solana Anchor 程序接口定义语言(IDL)

本文将带你探索 Anchor 框架中的 IDL(接口定义语言),这是一个自动生成的 JSON 文件,用于描述 Solana 程序的接口。我们将通过示例展示 IDL 的作用,解释 TypeScript 测试如何调用程序函数。


什么是 IDL?

IDL(Interface Definition Language)是 Anchor 生成的程序接口定义,存储在 target/idl/<program_name>.json 中,类似于 Solidity 的 ABI。它列出了程序的公共函数(instructions)、参数(args)和账户要求(accounts),为客户端(如 TypeScript)提供与链上程序交互的蓝图。


示例 1:函数调用与 IDL 映射

初始化项目

创建一个新项目:

anchor init anchor-function-tutorial
cd anchor-function-tutorial

启动本地验证器:

solana-test-validator

修改函数名

将默认的 initialize 函数改为 boaty_mc_boatface。编辑 programs/anchor-function-tutorial/src/lib.rs:

use anchor_lang::prelude::*;

declare_id!("3ytdGXdSqfQ5Z9NB9c5bGbkNqkzVPkpijs4hj4BeoAa7");

#[program]
pub mod anchor_function_tutorial {
    use super::*;

    pub fn boaty_mc_boatface(ctx: Context<Initialize>) -> Result<()> {
        msg!("Boaty says hi!");
        Ok(())
    }
}

#[derive(Accounts)]
pub struct Initialize {}

更新测试

编辑 tests/anchor-function-tutorial.ts:

it("Call boaty mcboatface", async () => {
    const tx = await program.methods.boatyMcBoatface().rpc();
    console.log("Your transaction signature", tx);
});

运行测试:

anchor test --skip-local-validator

测试如何定位函数?

Anchor 在构建时生成 IDL(target/idl/anchor_function_tutorial.json):

{
  "version": "0.1.0",
  "name": "anchor_function_tutorial",
  "instructions": [
    {
      "name": "boatyMcBoatface",
      "accounts": [],
      "args": []
    }
  ],
  "metadata": {
    "address": "3ytdGXdSqfQ5Z9NB9c5bGbkNqkzVPkpijs4hj4BeoAa7"
  }
}
  • 解析
    • "instructions":列出公共函数,类似 Solidity 的外部函数。
    • TypeScript 的 program.methods 根据 IDL 映射函数名,生成调用逻辑。

Anchor 0.30.x 后的命名规则

如果在 Anchor 0.30.0 及以上版本(如 0.30.1):

  • 函数名:保留 Rust 的蛇形命名(如 boaty_mc_boatface),不再转换为驼峰式(如 boatyMcBoatface)。
    • 原因:提升 Rust 代码与 IDL 的一致性,响应社区反馈。
  • 参数和账户名:仍使用驼峰式(如 firstArg、anotherSigner),适配 JavaScript/TypeScript 惯例。

测试调用注意

await program.methods.boatyMcBoatface();   // 正确,客户端仍需驼峰式
await program.methods.boaty_mc_boatface(); // 可行但不推荐
  • 经验建议:尽管 IDL 使用蛇形命名,建议在前端保持驼峰式调用,以符合生态习惯。

示例 2:带参数的算术函数

添加加减法函数

更新 lib.rs,实现加法和减法(Solana 不支持直接返回值,需用 msg! 输出):

use anchor_lang::prelude::*;

declare_id!("3ytdGXdSqfQ5Z9NB9c5bGbkNqkzVPkpijs4hj4BeoAa7");

#[program]
pub mod anchor_function_tutorial {
    use super::*;

    pub fn add(ctx: Context<Empty>, a: u64, b: u64) -> Result<()> {
        let sum = a + b;
        msg!("Sum is {}", sum);
        Ok(())
    }

    pub fn sub(ctx: Context<Empty>, a: u64, b: u64) -> Result<()> {
        let difference = a - b;
        msg!("Difference is {}", difference);
        Ok(())
    }
}

#[derive(Accounts)]
pub struct Empty {}

更新测试

编辑 tests/anchor-function-tutorial.ts:

it("Should add", async () => {
    const tx = await program.methods.add(new anchor.BN(1), new anchor.BN(2)).rpc();
    console.log("Your transaction signature", tx);
});

it("Should subtract", async () => {
    const tx = await program.methods.sub(new anchor.BN(10), new anchor.BN(3)).rpc();
    console.log("Your transaction signature", tx);
});

运行测试:

anchor test --skip-local-validator

生成的 IDL

  "instructions": [
    {
      "name": "add",
      "accounts": [],
      "args": [
        {
          "name": "a",
          "type": "u64"
        },
        {
          "name": "b",
          "type": "u64"
        }
      ]
    },
    {
      "name": "sub",
      "accounts": [],
      "args": [
        {
          "name": "a",
          "type": "u64"
        },
        {
          "name": "b",
          "type": "u64"
        }
      ]
    }
  ],

账户结构体详解

Context 与结构体命名

函数中的 ctx: Context 指定账户上下文,T 是自定义结构体,名称(如 Initialize 或 Empty)任意,只要与函数签名一致。

#[derive(Accounts)] 的作用

这是 Anchor 的 Rust 属性宏,解析结构体字段并映射到 IDL 的 accounts。空结构体(如 Empty)生成空的 accounts 数组。

非空账户示例

更新 lib.rs:

use anchor_lang::prelude::*;

declare_id!("3ytdGXdSqfQ5Z9NB9c5bGbkNqkzVPkpijs4hj4BeoAa7");

#[program]
pub mod anchor_function_tutorial {
    use super::*;

    pub fn non_empty_account_example(ctx: Context<NonEmptyAccountExample>) -> Result<()> {
        msg!("Signers present");
        Ok(())
    }
}

#[derive(Accounts)]
pub struct NonEmptyAccountExample<'info> {
    signer: Signer<'info>,
    another_signer: Signer<'info>,
}

构建:

anchor build

生成的 IDL 中的 instructions 部分为:

  "instructions": [
    {
      "name": "nonEmptyAccountExample",
      "accounts": [
        {
          "name": "signer",
          "isMut": false,
          "isSigner": true
        },
        {
          "name": "anotherSigner",
          "isMut": false,
          "isSigner": true
        }
      ],
      "args": []
    }
  ]
  • 变化
    • 函数名:nonEmptyAccountExample(驼峰式)。
    • 账户名:signer 和 anotherSigner(another_signer 转为驼峰式)。
  • Signer:表示交易签名者,类似 Ethereum 的 tx.origin。

示例 3:综合应用

完整代码

use anchor_lang::prelude::*;

declare_id!("3ytdGXdSqfQ5Z9NB9c5bGbkNqkzVPkpijs4hj4BeoAa7");

#[program]
pub mod anchor_function_tutorial {
    use super::*;

    pub fn function_a(ctx: Context<NonEmptyAccountExample>) -> Result<()> {
        msg!("Function A called");
        Ok(())
    }

    pub fn function_b(ctx: Context<Empty>, first_arg: u64) -> Result<()> {
        msg!("Function B with arg {}", first_arg);
        Ok(())
    }
}

#[derive(Accounts)]
pub struct NonEmptyAccountExample<'info> {
    signer: Signer<'info>,
    another_signer: Signer<'info>,
}

#[derive(Accounts)]
pub struct Empty {}

生成的 IDL

{
  "version": "0.1.0",
  "name": "anchor_function_tutorial",
  "instructions": [
    {
      "name": "functionA",
      "accounts": [
        {
          "name": "signer",
          "isMut": false,
          "isSigner": true
        },
        {
          "name": "anotherSigner",
          "isMut": false,
          "isSigner": true
        }
      ],
      "args": []
    },
    {
      "name": "functionB",
      "accounts": [],
      "args": [
        {
          "name": "firstArg",
          "type": "u64"
        }
      ]
    }
  ]
}
  • 映射
    • functionA:无参数,账户来自 NonEmptyAccountExample。
    • functionB:参数 first_arg 转为 firstArg,账户为空。

教程到此结束,更多,请,,https://t.me/+_QibemQqIIg1OTY1


http://www.kler.cn/a/595697.html

相关文章:

  • 【回归算法解析系列09】梯度提升回归树(GBRT, XGBoost, LightGBM)
  • Metasploit 跳板攻击
  • StarRocks 升级注意事项
  • django怎么配置404和500
  • VLAN综合实验报告
  • 【 Kubernetes 风云录 】- MutatingWebhook 实现自动注入
  • 解决 SQL Server 日常使用中的疑难杂症,提供实用解决方案
  • 阿里云国际站代理商:服务器网页如何应对恶意网络爬虫?
  • CI/CD管道
  • Apache Tomcat CVE-2025-24813 安全漏洞
  • MES汽车零部件制造生产监控看板大屏
  • FineBI_实现求当日/月/年回款金额分析
  • electron-builder创建桌面应用
  • 【MCP】如何解决duckduckgo MCP 命令执行错误
  • 数据库—sql语法基础
  • 深入解读《白帽子讲 Web 安全》之业务逻辑安全
  • zephyr-中国跨国并购数据(1997-2024.3.8)
  • 虚幻统一管理创建的标签
  • 蓝桥与力扣刷题(蓝桥 三角形面积)
  • wps字符很分散