Solana系列文章第3篇,在上一篇,我们使用了Sol在线IDEsolpg部署了一个简单的favorites程序,对于较大的项目,我们通常需要在本地进行工程化开发,在本地使用Anchor构建程序
Solana 系列文章第 3 篇,在上一篇,我们使用了 Sol 在线 IDE solpg 部署了一个简单的 favorites 程序,对于较大的项目,我们通常需要在本地进行工程化开发,在本地使用 Anchor 构建程序,这就是今天这篇文章的内容:
create-solana-dapp 新建工程 在开始之前,我们需要准备好开发 Solana DApp 所需的环境, 整个安装过程大体上根据 Anchor 安装说明: https://www.anchor-lang.com/docs/installation ,这里是中文安装说明。
Anchor 是使用 Rust 开发的,我们需要安装 Rust 来编译Anchor,后面也需要用 Rust 来编译 Solana 合约,因此我们先安装 Rust。
安装 Rust 推荐使用 rustup , 这样方便之后我们切换不同的rust 版本:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh 在弹出的安装选项中,选择默认选项即可。

如果网络不好,可能等待会比较长。
安装完成后,可以用 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.
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
DApp 需要在前端和 Solana 链,我们用 NVM 来安装管理不同的 Node.js 版本, 参考这里。
安装 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 命令会提示输入项目名称、前端模版框架:

cd favorites 项目结构有两个主要的目录:
anchor/:存放 Anchor 工程代码代码。src/:存放前端应用代码。在项目创建完成后,我们可以 VS Code 打开工程,我们需要编写、编译并部署智能合约。
在 anchor/programs 目录下,你会看到默认生成的 Anchor 合约示例。以 favorites 为例,打开 anchor/programs/favorites/src/lib.rs,用上一篇文章的 favorites 替换 lib.rs 。
在项目 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/ 目录下生成一系列构建的文件,最重要的几个文件有:
target/deploy/<program-name>.so ),这是最终部署到 Solana 链上的可执行文件(ELF 文件)。target/deploy/<program-name>-keypair.json), 在 anchor deploy 时,Anchor CLI 会使用此 Keypair 的 公钥 注册为 Program ID。target/idl/<program-name>.json) ,里面包含了程序的程序 ID,以及所有方法、数据结构等描述,以后客户端需要依靠 IDL文件来进行对智能合约的调用。部署合约前,我们需要确定部署的集群,以及部署程序的账号,这些是在 Anchor.toml中配置的。
Anchor.toml 是 Anchor 框架 特有的项目配置文件,用来配置程序、网络和钱包选项。决定"部署到哪、用哪个钱包、项目中包含哪些程序。
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/ ,链接本地集群查询账号信息:

使用 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 替换
在 anchor 目录下,通过以下命令安装:anchor-bankrun:
npm install anchor-bankrun 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 参数, 可参考相关的文档 。
在项目根目录下,运行以下命令:
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.toml 和 lib.rs 中的 program id 。anchor test 进行合约测试,测试用例会使用前面的IDL 文件和程序 ID,并使用 bankrun 进行合约测试。如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!