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

  • Tiny熊
  • 更新于 10小时前
  • 阅读 66

Solana系列文章第3篇,在上一篇,我们使用了Sol在线IDEsolpg部署了一个简单的favorites程序,对于较大的项目,我们通常需要在本地进行工程化开发,在本地使用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 版本:

> anchro --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 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,以及所有方法、数据结构等描述,客户端就是通过这个文件来进行对智能合约的调用。

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(如模拟各种错误情况) 等。

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 进行合约测试。
点赞 1
收藏 1
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
Tiny熊
Tiny熊
0xD682...E8AB
登链社区发起人 通过区块链技术让世界变得更好而尽一份力。