这次一定好好学 Solana (6) : 本地构建部署合约及前端调用

  • dgu
  • 发布于 2天前
  • 阅读 259

在上一节中,我们通过Playground体验了Solana合约的开发和调用。本文将带你使用本地开发环境实现这一过程,并通过TypeScript调用合约。如果你已经按照之前的章节配置好本地开发环境,可以开始动手实践了!我们先用最简单的合约测试,然后用上一节的例子测试,可以学

上一节 中,我们通过 Playground 体验了 Solana 合约的开发和调用。本文将带你使用本地开发环境实现这一过程,并通过 TypeScript 调用合约。如果你已经按照 之前的章节 配置好本地开发环境,可以开始动手实践了!

我们先用最简单的合约测试, 然后用上一节的例子测试, 可以学习 ts 里面怎么创建 PDA 账户


准备本地开发环境

更新工具

确保本地开发环境为最新版本,运行以下命令升级:

agave-install update

你可能会疑惑:为什么是 agave 而不是 solana
其实,Solana Labs 的官方仓库已归档(archive),现在由 Anza 团队(由 Solana Labs 前高管和核心工程师组成)全面接手开发。Anza 的主要产品包括:

  • Agave:从 Solana Labs fork 的验证客户端,已被 Solana 主网采用,目标 2025 年实现 1M TPS。
  • Kit:Solana JavaScript SDK,相当于 @solana/web3.js 的 2.0 版本。
  • Move:支持 Move 语言的改造,目前进展有限。
  • Rust/C 工具链:编译相关工具。

而我们使用的 Anchor 框架则由 Backpack 钱包团队(coral-xyz)开发。
小贴士:原生 Rust 开发据说比 Anchor 更省 gas,但对于初学者来说,Anchor 的快速上手优势更重要。

配置环境

solana config set -ud    # 设置为开发网(devnet)
solana-keygen new        # 生成默认钱包
solana airdrop 2         # 领取 2 SOL
solana-test-validator    # 启动本地节点
  • 本地测试:用 localnet 快速验证,配合 Solana Explorer 查看本地交易。
  • 开发网(devnet):如需用 devnet,可参考 这篇文章 对比各 RPC 性能。
  • Ping 测试:可以用 solana ping 检查你与 RPC 的连接速度, 需要付 gas。

创建项目

初始化一个 Anchor 项目:

anchor init demo
cd demo

合约代码 lib.rs 我就不展示了, 就是最简单的 hello world, 大家自己看

查看与修改 Program Account

solana 是部署之前就生成 Program Account 而不是部署完之后给你返回, 跟其他链不太一样

查看项目的 Program Address:

anchor keys list
# 或
solana address -k target/deploy/demo-keypair.json

两条命令结果一致,返回当前项目的 Program ID。

如果需要修改 Program Address:
场景:

  • 链上销毁合约 (close) 后重新部署, 不能用老的 key pair
  • 在不同 cluster 环境, 希望合约地址不一样
  1. 生成新密钥对:
    solana-keygen new --outfile target/deploy/demo-keypair.json
    solana address -k target/deploy/demo-keypair.json
  2. 同步到 lib.rs
    anchor keys sync

注意:若不打算升级程序,可销毁私钥以确保安全。

构建项目

anchor build

构建后,合约二进制文件生成在 target/deploy/demo.so,后续部署的就是这个文件。

项目结构

├── Anchor.toml           # Anchor 配置文件
├── programs              # 合约代码目录
│   └── demo              # 合约子目录
├── target                # 编译输出目录
│   ├── deploy
│   │   └── demo-keypair.json  # Program Account 私钥
│   │   └── demo.so       # 合约二进制文件
│   ├── idl               # IDL 文件, 描述合约
│   └── types             # TypeScript 类型, 方便 ts 代码调用合约
├── tests                 # 测试目录
│   └── demo.ts           # 测试文件
└── migrations            # 部署脚本
    └── deploy.ts

部署合约

配置部署

Anchor.toml 中指定部署网络和钱包:

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

也可通过命令行指定 RPC:

anchor deploy --provider.cluster https://devnet.solana.rpcpool.com

查看 Program 信息

部署后,查看详情:

solana program show <Program-ID>

测试合约

本地测试

anchor test
  • 默认使用 localnet,自动启动节点、部署合约并运行测试。
  • 注意:若已手动启动 solana-test-validator,会因端口冲突报错。
  • 缺点:测试后节点关闭,无法在 Explorer 查看交易,可在 .anchor/program-logs 查看日志。
  • 改进:用 --skip-local-validator 配合手动启动的节点:
    anchor test --skip-local-validator

重新部署

修改代码后:

anchor build
anchor test --skip-local-validator

销毁合约

销毁后 Program ID 无法再次使用,但可回收 SOL, 可以给我们回一回血:

solana program close <Program-ID> --bypass-warning

示例:

solana balance                   # 500000008.72812742 SOL
solana program close <Program-ID> --bypass-warning  # 回收 1.26686616 SOL
solana balance                   # 500000009.994988561 SOL

注意: 再次部署会报错,必须重新生成 Program ID, 参照上面的步骤。


TypeScript 调用合约

代码结构很简单

导入依赖
定义并创建 RPC 连接
加载钱包
获取 Program
调用指令

测试脚本

tests 目录下创建 mytest.ts

import * as anchor from "@coral-xyz/anchor";
import { Program } from "@coral-xyz/anchor";
import { Demo } from "../target/types/demo";
import { Connection, Keypair } from "@solana/web3.js";
import * as fs from "fs";

// 本地节点 RPC
const RPC_URL = "http://127.0.0.1:8899";
const connection = new Connection(RPC_URL, "confirmed");

// 加载钱包
const walletKeypair = Keypair.fromSecretKey(
  new Uint8Array(JSON.parse(fs.readFileSync("/Users/yc/.config/solana/id.json", "utf-8")))
);
const wallet = new anchor.Wallet(walletKeypair);
const provider = new anchor.AnchorProvider(connection, wallet, { preflightCommitment: "confirmed" });
anchor.setProvider(provider);

// 获取 Program
const program = anchor.workspace.demo as Program<Demo>;

async function main() {
  console.log("Using wallet:", wallet.publicKey.toBase58());

  try {
    const tx = await program.methods
      .initialize()
      .accounts({ signer: wallet.publicKey })
      .signers([walletKeypair])
      .rpc();
    console.log("Transaction Signature:", tx);
  } catch (error) {
    console.error("Transaction failed:", error);
  }
}

main();

执行测试

当前项目安装 ts-node(若未安装):

npm install --save-dev ts-node

运行:

npx ts-node tests/mytest.ts

查看交易详情

explorer 是支持 localnet 的

image.png

在本地测试之前 PDA 账户的例子

之前的 PDA 例子 我在 GitHub 提供代码,我本地的版本为:

  • anchor-cli 0.31.0
  • solana-cli 2.1.17

说明: 调用代码中可能遇到编译错误,暂时需用 as any 规避, 这一点坑了大概 2 个小时, 可能是新版的问题:

const txId = await program.methods
  .setFavorites(favoriteNumber, favoriteColor)
  .accounts({
    user: userKeypair.publicKey,
    fav: favoritesPda,
    systemProgram: SystemProgram.programId,
  } as any)  // 这里
  .signers([userKeypair])
  .rpc();

总结

  • 本地开发:用 solana-test-validatoranchor test 快速验证。
  • 部署与销毁:灵活管理 Program ID 和 SOL。
  • TypeScript 调用:结合 Anchor 和 @solana/web3.js,轻松与合约交互。

赶快动手试试吧!有问题欢迎留言讨论。

点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
dgu
dgu
江湖只有他的大名,没有他的介绍。