Solana 开发系列 3 - 使用 Anchor 开发程序

Solana 系列文章第 3 篇,在上一篇,我们使用了 Sol 在线 IDE solpg 部署了一个简单的 favorites 程序,对于较大的项目,我们通常需要在本地进行工程化开发,在本地使用 Anchor 构建程序,这就是今天这篇文章的内容:

  1. Anchor 开发环境搭建
  2. 使用 create-solana-dapp 新建工程
  3. 使用 Anchor 编译与部署合约
  4. 使用 Bankrun 测试合约

Anchor 开发环境搭建

在开始之前,我们需要准备好开发 Solana DApp 所需的环境, 整个安装过程大体上根据 Anchor 安装说明: https://www.anchor-lang.com/docs/installation ,这里是中文安装说明

Anchor 是使用 Rust 开发的,我们需要安装 Rust 来编译Anchor,后面也需要用 Rust 来编译 Solana 合约,因此我们先安装 Rust。

1. 安装 Rust

安装 Rust 推荐使用 rustup , 这样方便之后我们切换不同的rust 版本:

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

在弹出的安装选项中,选择默认选项即可。

image-20250114205341575

如果网络不好,可能等待会比较长。

安装完成后,可以用 rustup --version 看一下当前的版本:

rustup --version rustup 1.27.1 (54dd3d00f 2024-04-24) info: This is the version for the rustup toolchain manager, not the rustc compiler. info: The currently active `rustc` version is `rustc 1.79.0 (129f3b996 2024-06-10)`

可以看到我这里的版本是 rustup 1.27.1, rustc 为 1.79.0 , 此时说明已经正确安装了 rust.

2. 安装 Solana CLI

Solana 命令行工具用于与 Solana 网络交互,包括部署和管理程序, 安装参考:https://solana.com/docs/intro/installation

sh -c "$(curl -sSfL https://release.anza.xyz/stable/install)"

stable 可以替换为指定的版本, 脚本执行后按提示添加环境变量,之后你可以这样验证安装是否成功:

> solana --version solana-cli 1.18.18 (src:83047136; feat:4215500110, client:SolanaLabs)

可以看到我这里的 solana 版本是 1.18.18

3. 安装前端工具

DApp 需要在前端和 Solana 链,我们用 NVM 来安装管理不同的 Node.js 版本, 参考这里

4. 安装 Anchor

安装 Anchor 推荐使用 avm (Anchor version manager) 来安装,使用 cargo 来安装(cargo 是 rust 的包管理工具):

cargo install --git https://github.com/coral-xyz/anchor avm --locked --force

我在这步安装遇到了一点问题,直到我把 rust 切换到 nightly,并且设置 CARGO_NET_GIT_FETCH_WITH_CLI 才搞定:

> rustup install nightly > export CARGO_NET_GIT_FETCH_WITH_CLI=true

由于 Solana 和 Anchor 都在不断的更新中,所依赖的 rust 相关工具链版本也在不断变化,这些版本问题确实有一点坑。

安装完成后,验证版本:

avm --version

然后用 avm 安装 Anchor :

> avm use latest

安装完成后,验证 anchor 版本:

> anchor --version anchor-cli 0.30.1

这样所需要的环境就安装好了。

新建工程

create-solana-dapp 是一个脚手架工具,为我们设置一个包含各种配置选项的 Solana Web 项目,包括 Next.js 客户端、Tailwind UI 库和一个简单的 Anchor 程序。

工程的完整代码,可以参考这里

现在我们来创建一个 favorites 工程:

npx create-solana-dapp

命令会提示输入项目名称、前端模版框架:

image-20250114220941879

cd favorites

项目结构有两个主要的目录:

  • anchor/:存放 Anchor 工程代码代码。
  • src/:存放前端应用代码。

使用 Anchor 编译与部署合约

在项目创建完成后,我们可以 VS Code 打开工程,我们需要编写、编译并部署智能合约。

1. 编写合约

anchor/programs 目录下,你会看到默认生成的 Anchor 合约示例。以 favorites 为例,打开 anchor/programs/favorites/src/lib.rs,用上一篇文章的 favorites 替换 lib.rs

2. 编译合约

在项目 anchor 目录下,运行以下命令编译合约:

anchor build

你可能会遇到错误:error: init_if_needed requires that anchor-lang be imported with the init-if-needed cargo feature

这是需要我们把 anchor/programs/favorites/cargo.toml 修改一下依赖的 feature :

... [dependencies] anchor-lang = { version = "0.30.1", features = ["init-if-needed"] } ...

Cargo.toml 文件是管理 Rust 项目依赖、编译配置、项目包管理及元信息的文件。决定“这个程序是如何编译、依赖什么库,以及采用哪些 Rust 特性”

再次运行 anchor build ,执行成功后,在 target/ 目录下生成一系列构建的文件,最重要的几个文件有:

  1. 编译出的程序(文件名:target/deploy/<program-name>.so ),这是最终部署到 Solana 链上的可执行文件(ELF 文件)。
  2. 程序的 Keypair(target/deploy/<program-name>-keypair.json), 在 anchor deploy 时,Anchor CLI 会使用此 Keypair 的 公钥 注册为 Program ID
  3. IDL 文件 ( target/idl/<program-name>.json) ,里面包含了程序的程序 ID,以及所有方法、数据结构等描述,以后客户端需要依靠 IDL文件来进行对智能合约的调用。

3. 部署合约

部署合约前,我们需要确定部署的集群,以及部署程序的账号,这些是在 Anchor.toml中配置的。

Anchor.tomlAnchor 框架 特有的项目配置文件,用来配置程序、网络和钱包选项。决定"部署到哪、用哪个钱包、项目中包含哪些程序

Anchor.toml 包含的所有配置项,可以在这里 找到,当下我们使用到的有:

[provider] cluster = "localnet" wallet = "~/.config/solana/id.json"

启动网络

这里配置的使用本地网络的集群,这个集群是通过 solana-test-validator 启动的。

运行 solana-test-validator 启动本地网络集群:

> solana-test-validator Ledger location: test-ledger Log: test-ledger/validator.log ⠉ Initializing... Waiting for fees to stabilize 1... Identity: Fzsq7WHnBVLCcwaeXnjYVYDsTuTT4izcPCHHFjbYasmK Genesis Hash: 3fzCr16ffwszZDrTYX3z4775PC1hMpfpxfur6HE83LAh Version: 1.18.18 Shred Version: 766 Gossip Address: 127.0.0.1:1024 TPU Address: 127.0.0.1:1027 JSON RPC URL: http://127.0.0.1:8899 WebSocket PubSub URL: ws://127.0.0.1:8900

准备部署账号

现在创建一个账号用来部署合约:

> solana-keygen new -o /Users/emmett/.config/solana/id.json Wrote new keypair to /Users/emmett/.config/solana/id.json ========================================================================== pubkey: 6oLiQn73H8EWnbo5sSuFx1V4KNAasBgFP39puLR9Emaw ========================================================================== Save this seed phrase and your BIP39 passphrase to recover your new keypair: test test test test test test ..... ==========================================================================

部署合约之前,需要确保本地有足够的 SOL 余额。你可以通过以下命令获取测试 SOL:

> solana airdrop 2 -u http://127.0.0.1:8899 Requesting airdrop of 2 SOL ...

-u 用来指定网络集群端点。

使用以下命令查询余额:

solana balance -u http://127.0.0.1:8899

也可以在浏览器上 https://explorer.solana.com/ ,链接本地集群查询账号信息:

image-20250115223151753

开始部署合约

使用 anchor deploy 部署合约

> anchor deploy Deploying cluster: http://127.0.0.1:8899 Upgrade authority: /Users/emmett/.config/solana/id.json Deploying program "favorites"... Program path: /Users/emmett/SolanaProject/favorites/anchor/target/deploy/favorites.so... Program Id: 2RGcHFUgJ4R8jxgQjLy1dF7p5kuUFK7aUKqyAxDcBnjH

部署成功后,控制台会打印出新部署的程序 ID。

小技巧,部署后,可以使用命令 anchor keys sync 把 Anchor.toml 和 lib.rs 中的 program id 更新一下

合约测试

Bankrun 是一个专门为 Solana 程序测试设计的、使用 NodeJS 进行测试框架, 提供了很多优秀的功能,例如:直接在内存中模拟 Solana 运行时环境,测试执行速度比传统方法快 10-100 倍,支持完整的账户状态控制(如设置账户余额、数据),丰富的测试 API(如模拟各种错误情况) 等。

Bankrun 现在已经被 liteSVM 替换

1. 安装 Bankrun

在 anchor 目录下,通过以下命令安装:anchor-bankrun

npm install anchor-bankrun

2. 编写测试

create-solana-dapp 创建工程时, 在 anchor/tests/ 目录下,已经包含了一个测试模版文件 favorites.spec.ts,我们用以下代码替换 favorites.spec.ts 文件。

// 导入必要的依赖 import * as anchor from '@coral-xyz/anchor' import { Program } from '@coral-xyz/anchor' import { PublicKey, SystemProgram } from '@solana/web3.js' import { BankrunProvider, startAnchor } from "anchor-bankrun"; // 导入程序类型定义,这是由 Anchor 自动生成的 import { Favorites } from '../target/types/favorites' // 导入程序的 IDL (Interface Description Language) 文件 const IDL = require("../target/idl/favorites.json"); // 定义程序 ID,应该与你部署的程序地址匹配 const PROGRAM_ID = new PublicKey("coUnmi3oBUtwtd9fjeAvSsJssXh5A5xyPbhpewyzRVF"); describe('favorites', () => { it('设置收藏', async () => { // 初始化 Bankrun 测试环境 const context = await startAnchor("", [{name: "favorites", programId: PROGRAM_ID}], []); // 创建 Bankrun Provider,用于与程序交互 const provider = new BankrunProvider(context); // 使用 IDL 和 Provider 创建程序实例 const favoritesProgram = new Program<Favorites>( IDL, provider, ); // 计算 PDA (Program Derived Address) // seeds: ["favorites", 用户公钥] const [favoritePda] = PublicKey.findProgramAddressSync( [ Buffer.from("favorites"), provider.wallet.publicKey.toBuffer() ], favoritesProgram.programId ) // 准备测试数据 const favoriteNumber = new anchor.BN(42) // 使用 BN 处理大数 const favoriteColor = "red" const hobbies = ["book", "sport", "programming"] // 调用程序的 set_favorites 指令 // Anchor 会自动推导所需的账户,无需手动指定 await favoritesProgram.methods .setFavorites( favoriteNumber, favoriteColor, hobbies ) .rpc() // 从链上获取账户数据并验证 const favoriteData = await favoritesProgram.account.favorites.fetch(favoritePda) // 验证存储的数据是否与输入匹配 expect(favoriteData.number.toString()).toEqual(favoriteNumber.toString()) expect(favoriteData.color).toEqual(favoriteColor) expect(favoriteData.hobbies).toEqual(hobbies) }) }) 

在 Anchor Bankrun 测试中不需要显式指定 accounts,Anchor 会根据指令(instruction)的定义自动推导所需的账户。

startAnchor 参数, 可参考相关的文档

3. 运行测试

在项目根目录下,运行以下命令:

anchor test

如果运行 anchor test 时出现错误:

Error: Your configured rpc port: 8899 is already in use

这是因为已经有一个 solana-test-validator 实例正在运行,而 Anchor 在运行测试时会尝试启动一个新的本地验证节点(也使用端口8899),所以会报错。

我们可以使用 --skip-local-validator--skip-deploy 参数来跳过本地验证节点和合约部署:

> anchor test --skip-local-validator --skip-deploy ... PASS tests/favorites.spec.ts (10.049 s) test favorites ✓ 设置收藏 (202 ms) Test Suites: 1 passed, 1 total Tests: 1 passed, 1 total Snapshots: 0 total Time: 10.097 s 

这样就完成了合约的测试了。

总结

我们在这篇文章中详细介绍了如何使用 Anchor 在本地搭建 Solana 开发环境, 主要是要注意 Rust 工具链的版本问题。

使用 create-solana-dapp 创建新的 Solana DApp 项目,并演示了通过 anchor 命令行工具来编译、部署、测试合约,主要的命令有:

  • 使用 anchor build 编译合约,会生成程序二进制文件、keypair、IDL文件。
  • 使用 anchor deploy 部署合约,会使用 keypair 部署合约,并更新 Anchor.tomllib.rs 中的 program id
  • 使用 anchor test 进行合约测试,测试用例会使用前面的IDL 文件和程序 ID,并使用 bankrun 进行合约测试。
  • 发表于 2025-01-18 21:26
  • 阅读 ( 6685 )
  • 学分 ( 762 )
  • 分类:Solana
  • 标签: Solana  IDL  Anchor 
点赞 7
收藏 3
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

1 条评论

请先 登录 后评论