本文详细讲解了如何在Solana上使用Anchor框架部署程序,并解释了Solana程序的可变性和与Ethereum的差异。通过代码示例和命令行操作,展示了程序的部署、升级和测试过程。
在本教程中,我们将从幕后看看 Anchor 如何部署 Solana 程序。
让我们看看 Anchor 在我们运行 anchor init deploy_tutorial
时为我们创建的测试文件:
describe("deploy_tutorial", () => {
// 配置客户端以使用本地集群。
anchor.setProvider(anchor.AnchorProvider.env());
const program = anchor.workspace.DeployTutorial as Program<DeployTutorial>;
it("Is initialized!", async () => {
// 在此添加你的测试。
const tx = await program.methods.initialize().rpc();
console.log("你的交易签名", tx);
});
});
它生成的启动程序应该很熟悉:
use anchor_lang::prelude::*;
declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
#[program]
pub mod deploy_tutorial {
use super::*;
pub fn initialize(ctx: Context<Initialize>) -> Result<()> {
Ok(())
}
}
#[derive(Accounts)]
pub struct Initialize {}
上述程序在哪里以及何时被部署?
合同唯一合理的部署地点是在测试文件中的这一行:
const program = anchor.workspace.DeployTutorial as Program<DeployTutorial>;
但这并没有意义,因为我们本该期望那是一个异步函数。
Anchor 在后台默默地部署程序。
对于来自其他面向对象语言的人来说,这可能看起来不寻常。Rust 没有对象或类。
在以太坊智能合约中,构造函数可以配置存储或设置字节码和不可变变量。
那么“部署步骤”到底在哪里?
(如果你仍在运行 Solana 验证器和 Solana 日志,建议你重启并清除这两个终端)
让我们进行常规设置。创建一个名为 program-deploy 的新 Anchor 项目,并确保在其他终端中运行验证器和日志。
与其运行 anchor test
,不如在终端中运行以下命令:
anchor deploy
在上面的日志截图中,我们可以看到程序被部署的时刻。
现在,令人感兴趣的部分是。再次运行 anchor deploy
:
程序被部署到同一地址,但这次是 升级,而非重新部署。
程序 ID 没有改变,程序被覆盖了。
这可能对以太坊开发者来说是一个震惊,因为在以太坊中假设是不可变的。
如果作者可以随意更改程序,那么这个程序有什么意义?确实可以使 Solana 程序不可变。假设作者会先部署可变版本,随着时间的推移且未发现任何错误后,再将其重新部署为不可变。
在功能上,这与管理员控制的代理没有任何区别,后期所有者将所有权放弃给零地址。但可以说,Solana 模型更干净,因为以太坊代理可能会出问题。
另一个含义是:Solana 不需要 delegatecall,因为它不需要。
在 Solidity 合约中,delegatecall 的主要用途是通过发出 delegatecalls 到新实现合约来升级代理合约的功能能力。然而,由于 Solana 中程序的字节码可以升级,因此无需调用实现合约。
另一个推论是:Solana 没有 Solidity 那种不可变变量(只能在构造函数中设置的变量)。
由于 Anchor 默认重新部署程序,让我们演示如何在不重新部署的情况下运行测试。
将测试更改为以下内容:
import * as anchor from "@coral-xyz/anchor";
import { Program } from "@coral-xyz/anchor";
import fs from 'fs'
let idl = JSON.parse(fs.readFileSync('target/idl/deployed.json', 'utf-8'))
describe("deployed", () => {
// 配置客户端以使用本地集群。
anchor.setProvider(anchor.AnchorProvider.env());
// 更改为你的 programID
const programID = "6p29sM4hEK8ZFT5AvsGJQG5nKUtHBKs13iVL6juo5Uqj";
const program = new Program(idl, programID, anchor.getProvider());
it("Is initialized!", async () => {
// 在此添加你的测试。
const tx = await program.methods.initialize().rpc();
console.log("你的交易签名", tx);
});
});
在你运行测试之前,建议清除 Solana 日志的终端并重启 solana-test-validator。
现在,使用以下测试命令:
anchor test --skip-local-validator --skip-deploy
现在查看日志终端:
我们看到初始化指令已被执行,但程序既没有被部署也没有被升级,因为我们在 anchor test 中使用了 --skip-deploy
参数。
练习:要查看程序的字节码实际上发生了变化,部署两个打印不同 msg!
值的合约。具体步骤如下:
initialize
函数,包括一个 msg!
语句,将字符串写入日志。anchor deploy
anchor test --skip-local-validator --skip-deploy
msg!
中的字符串你应该观察到消息字符串的变化,但程序 ID 保持不变。
本教程是 Solana 课程 的一部分。
最初发布于 2024 年 2 月 12 日
- 原文链接: rareskills.io/post/solan...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!