Rust的Anchor框架CPI生成工具anchor-generate-cpi-crate使用,自动化生成跨程序调用接口提升Solana开发效率

Rust的Anchor框架CPI生成工具anchor-generate-cpi-crate使用,自动化生成跨程序调用接口提升Solana开发效率

使用说明

anchor-gen工具可以从JSON IDL自动生成Anchor程序的跨程序调用(CPI)客户端库。

在一个新的crate中,只需编写以下代码:

// 从IDL文件生成CPI客户端库
anchor_gen::generate_cpi_crate!("../../examples/govern-cpi/idl.json");

// 声明程序ID
declare_id!("GjphYQcbP1m3FuDyCTUJf2mUMxKPE3j6feWU1rxvC7Ps");

这将为你的IDL生成一个功能完整的Rust CPI客户端。

完整示例

// Cargo.toml
[package]
name = "my_cpi_client"
version = "0.1.0"
edition = "2021"

[dependencies]
anchor-lang = "0.24.2"
anchor-gen = "0.4.0"

// src/lib.rs
anchor_gen::generate_cpi_crate!("path/to/your/idl.json");

declare_id!("YourProgramIDHere");

// 生成的CPI客户端使用方法示例
pub fn make_cpi_call(
    program: &Program<MyProgram>,
    accounts: MyInstructionAccounts,
    data: MyInstructionData,
) -> Result<()> {
    let cpi_ctx = CpiContext::new(program, accounts);
    my_program::cpi::my_instruction(cpi_ctx, data)?;
    Ok(())
}

注意事项

  1. 该工具不支持旧版IDL格式,如需转换旧版IDL,请使用命令:anchor idl convert idl.json
  2. 更多示例可以在项目示例目录中找到
  3. 许可证:Apache-2.0

安装方式

在项目目录中运行以下Cargo命令:

cargo add anchor-generate-cpi-crate

或者在Cargo.toml中添加以下行:

anchor-generate-cpi-crate = "0.4.0"

这个工具可以显著提升Solana开发效率,通过自动化生成跨程序调用接口,减少手动编写CPI客户端代码的工作量。

完整示例Demo

下面是一个完整的CPI客户端使用示例:

// Cargo.toml
[package]
name = "governance_cpi_client"
version = "0.1.0"
edition = "2021"

[dependencies]
anchor-lang = "0.24.2"
anchor-gen = "0.4.0"

// src/lib.rs
anchor_gen::generate_cpi_crate!("governance_program_idl.json");

declare_id!("GovER5Lthms3bLBqWub97yVrMmEogzX7xNjdXpPPCVZw");

// 使用生成的CPI客户端调用治理程序的create_proposal指令
pub fn create_governance_proposal(
    program: &Program<GovernanceProgram>,  // 传入治理程序实例
    accounts: governance::CreateProposalAccounts,  // 指令所需的账户
    title: String,  // 提案标题
    description: String,  // 提案描述
) -> Result<()> {
    // 创建指令数据
    let data = governance::CreateProposalData {
        title,
        description,
    };
    
    // 创建CPI上下文
    let cpi_ctx = CpiContext::new(program, accounts);
    
    // 调用生成的CPI方法
    governance::cpi::create_proposal(cpi_ctx, data)?;
    
    Ok(())
}

这个示例展示了如何:

  1. 创建一个新的crate用于CPI客户端
  2. 从IDL文件生成CPI客户端代码
  3. 声明程序ID
  4. 使用生成的CPI客户端调用特定指令

生成的CPI客户端会自动包含程序中定义的所有指令及其对应的账户结构和数据类型,大大简化了跨程序调用的开发工作。


1 回复

Rust的Anchor框架CPI生成工具anchor-generate-cpi-crate使用指南

简介

anchor-generate-cpi-crate是一个用于Solana开发的Rust工具,它能自动化生成跨程序调用(Cross-Program Invocation, CPI)接口,显著提升使用Anchor框架开发Solana程序的效率。

该工具通过解析Anchor程序的IDL(Interface Description Language)文件,自动生成类型安全的CPI客户端代码,避免了手动编写CPI调用的繁琐工作。

安装方法

首先确保你已经安装了Rust和Cargo,然后运行:

cargo install anchor-generate-cpi-crate

基本使用方法

1. 生成CPI客户端

在Anchor项目根目录下运行:

anchor-generate-cpi-crate --program-id <你的程序ID> --idl <idl文件路径> --out-dir <输出目录>

示例:

anchor-generate-cpi-crate --program-id my_program --idl target/idl/my_program.json --out-dir client

2. 在项目中使用生成的CPI客户端

在需要使用CPI的模块中:

use client::MyProgramCpiClient;

// 初始化客户端
let cpi_client = MyProgramCpiClient::new(program_id, accounts);

// 调用程序方法
cpi_client.my_method(args)?;

高级功能

自定义生成选项

anchor-generate-cpi-crate \
    --program-id my_program \
    --idl target/idl/my_program.json \
    --out-dir client \
    --module-name my_cpi \
    --skip-types

在build.rs中集成

fn main() {
    anchor_generate_cpi_crate::Generator::new()
        .program_id("my_program")
        .idl("target/idl/my_program.json")
        .out_dir("client")
        .generate()
        .unwrap();
}

示例项目结构

my_anchor_project/
├── programs/
│   └── my_program/
├── client/          # 生成的CPI客户端
│   ├── mod.rs
│   └── ...
├── tests/
└── Cargo.toml

实际使用示例

假设有一个Anchor程序定义如下:

#[program]
mod my_program {
    pub fn initialize(ctx: Context<Initialize>, data: u64) -> Result<()> {
        // 初始化逻辑
        Ok(())
    }
}

生成的CPI客户端可以这样使用:

use client::MyProgramCpiClient;

// 在另一个程序的CPI调用中
let accounts = client::Initialize {
    account: ctx.accounts.my_account.to_account_info(),
    system_program: ctx.accounts.system_program.to_account_info(),
};

let cpi_client = MyProgramCpiClient::new(
    ctx.accounts.my_program.to_account_info(),
    accounts,
);

cpi_client.initialize(42)?;

完整示例demo

下面是一个完整的从Anchor程序定义到使用CPI客户端的示例:

  1. 首先定义一个Anchor程序:
// programs/my_program/src/lib.rs
use anchor_lang::prelude::*;

declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");

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

    pub fn create_user(ctx: Context<CreateUser>, name: String, age: u8) -> Result<()> {
        let user = &mut ctx.accounts.user;
        user.name = name;
        user.age = age;
        user.authority = *ctx.accounts.authority.key;
        Ok(())
    }
}

#[account]
pub struct User {
    pub name: String,
    pub age: u8,
    pub authority: Pubkey,
}

#[derive(Accounts)]
pub struct CreateUser<'info> {
    #[account(init, payer = authority, space = 8 + 32 + 1 + 4 + 100)]
    pub user: Account<'info, User>,
    #[account(mut)]
    pub authority: Signer<'info>,
    pub system_program: Program<'info, System>,
}
  1. 构建项目生成IDL文件后,使用工具生成CPI客户端:
anchor-generate-cpi-crate \
    --program-id Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS \
    --idl target/idl/my_program.json \
    --out-dir client
  1. 在另一个程序中调用CPI:
// programs/another_program/src/lib.rs
use anchor_lang::prelude::*;
use client::MyProgramCpiClient;

declare_id!("AnotherProgramId11111111111111111111111111111");

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

    pub fn call_create_user(ctx: Context<CallCreateUser>, name: String, age: u8) -> Result<()> {
        // 准备CPI账户
        let accounts = client::CreateUser {
            user: ctx.accounts.user.to_account_info(),
            authority: ctx.accounts.authority.to_account_info(),
            system_program: ctx.accounts.system_program.to_account_info(),
        };

        // 创建CPI客户端
        let cpi_client = MyProgramCpiClient::new(
            ctx.accounts.my_program.to_account_info(),
            accounts,
        );

        // 调用CPI方法
        cpi_client.create_user(name, age)?;

        Ok(())
    }
}

#[derive(Accounts)]
pub struct CallCreateUser<'info> {
    #[account(mut)]
    pub user: UncheckedAccount<'info>,
    #[account(mut)]
    pub authority: Signer<'info>,
    pub my_program: Program<'info, MyProgram>,
    pub system_program: Program<'info, System>,
}

优势

  1. 类型安全 - 所有CPI调用都经过类型检查
  2. 减少样板代码 - 自动生成账户结构和上下文
  3. 与IDL同步 - 当IDL变化时只需重新生成
  4. 提高开发效率 - 减少手动编写CPI的时间

注意事项

  • 确保在Anchor构建生成IDL后再运行此工具
  • 生成的代码应与Anchor版本兼容
  • 对于大型项目,考虑将生成步骤集成到构建过程中

通过使用anchor-generate-cpi-crate,Solana开发者可以专注于业务逻辑而不是繁琐的CPI接口编写,大幅提升开发效率和代码质量。

回到顶部