Solana 程序:支持升级与无构造函数实现

  • 0xE
  • 发布于 2025-03-22 09:23
  • 阅读 400

Solana 程序通过 Anchor 部署无需构造函数,默认可升级且可转为不可变,简化了状态管理与升级流程。

Anchor 初始化与程序部署

当你运行 anchor init deploy_tutorial 时,Anchor 会生成一个默认的测试文件:

describe("deploy_tutorial", () => {
  // Configure the client to use the local cluster.
  anchor.setProvider(anchor.AnchorProvider.env());

  const program = anchor.workspace.DeployTutorial as Program<DeployTutorial>;

  it("Is initialized!", async () => {
    // Add your test here.
    const tx = await program.methods.initialize().rpc();
    console.log("Your transaction signature", tx);
  });
});

对应的程序代码如下:

use anchor_lang::prelude::*;

declare_id!("A5Y9992TvbUD8Q7bmaCY9j9wztwgcFweUBV5y1JXEyjo");

#[program]
pub mod deploy_tutorial {
    use super::*;

    pub fn initialize(ctx: Context<Initialize>) -> Result<()> {
        msg!("Greetings from: {:?}", ctx.program_id);
        Ok(())
    }
}

#[derive(Accounts)]
pub struct Initialize {}

那么,这个程序究竟在何时何地被部署呢?

乍看之下,测试文件中的这行代码似乎与部署有关:

const program = anchor.workspace.DeployTutorial as Program<DeployTutorial>;

但这显然不是部署的实际位置,因为它只是定义了一个程序实例,而非异步部署操作。实际上,Anchor 在后台默默完成了程序的部署工作,通常在运行 anchor test 时自动执行。

Solana 程序没有构造函数

对于习惯 Solidity 的开发者来说,Solana 程序没有构造函数可能显得反常。Rust 本身没有传统意义上的类或对象,因此 Solana 程序的部署逻辑也与以太坊智能合约截然不同。

在以太坊中,构造函数用于初始化存储、设置字节码或定义不可变变量。而在 Solana 中,“部署步骤”又是如何实现的呢?

手动部署 Solana 程序

让我们通过一个实验来验证部署过程。创建一个名为 deploy 的新 Anchor 项目,并确保在后台运行 solana-test-validator 和 solana logs。

运行 anchor build 编译程序后,跳过 anchor test,直接在终端执行:

anchor deploy

输出日志如下:

Transaction executed in slot 465:
  Signature: 5SNBgNimNvRQRanTXrriHoWsmXmu1NFtXLqGU4KLRGuAFeQApvbZPbGCifAffbkCpB7V94hh3gvHrkYy5ozMFUtX
  Status: Ok
  Log Messages:
    Program 11111111111111111111111111111111 invoke [1]
    Program 11111111111111111111111111111111 success
    Program BPFLoaderUpgradeab1e11111111111111111111111 invoke [1]
    Program 11111111111111111111111111111111 invoke [2]
    Program 11111111111111111111111111111111 success
    Deployed program A5Y9992TvbUD8Q7bmaCY9j9wztwgcFweUBV5y1JXEyjo
    Program BPFLoaderUpgradeab1e11111111111111111111111 success

日志显示,程序已被成功部署,程序 ID 为 A5Y9992TvbUD8Q7bmaCY9j9wztwgcFweUBV5y1JXEyjo。

再次部署:程序升级

有趣的是,再次运行 anchor deploy,会得到以下结果:

Transaction executed in slot 657:
  Signature: 2Yik43HpT6h4tZ9zDmhtsqqrVFZsbSaU7se6MpsCPJ32xzg1E5V8WuzRgQc5LNJS7hyNo5C9xSeZo7Q2Jqzrh2oA
  Status: Ok
  Log Messages:
    Program BPFLoaderUpgradeab1e11111111111111111111111 invoke [1]
    Upgraded program A5Y9992TvbUD8Q7bmaCY9j9wztwgcFweUBV5y1JXEyjo
    Program BPFLoaderUpgradeab1e11111111111111111111111 success

这次日志显示程序被“升级”(Upgraded),而非重新部署。程序 ID 未变,表明 Solana 的程序字节码被直接覆盖。

Solana 程序默认可变

这对于以太坊开发者来说可能有些奇怪,因为以太坊合约默认不可变,而 Solana 程序默认是可升级的。程序作者可以随时更新字节码,这引发一个问题:如果程序可以随意更改,其可信度如何保证?

Solana 提供了一种解决方案:程序可以选择部署为不可变版本。开发者通常会先部署可变程序进行测试,待确认无误后,再将其升级为不可变状态。这种模式类似于以太坊中代理合约的管理员权限最终转移至零地址,但 Solana 的实现更为简洁,避免了代理模式中常见的复杂性。

无需 delegatecall

在 Solidity 中,delegatecall 常用于通过代理调用新实现合约来升级功能。然而,Solana 的可升级字节码设计消除了对 delegatecall 的需求——开发者只需直接更新程序即可。

无不可变变量

另一个推论是,Solana 没有类似 Solidity 的不可变变量(即在构造函数中设置且不可更改的变量)。由于没有构造函数,程序的状态初始化通常通过普通指令完成。

不重新部署运行测试

Anchor 默认在运行 anchor test 时重新部署程序。但我们可以通过参数跳过部署,测试已有程序。清除日志并重启 solana-test-validator 后,运行:

anchor test --skip-local-validator --skip-deploy

日志输出:

  Signature: 2go5NbbWMFAbXNvTiNRn5o5x9h7mBWSa649p7ZJDs2PotqhZMyEMMyDKD86QNnjEFvjCHq72R3giGXATDLX1Tiav
  Status: Ok
  Log Messages:
    Program A5Y9992TvbUD8Q7bmaCY9j9wztwgcFweUBV5y1JXEyjo invoke [1]
    Program log: Instruction: Initialize
    Program log: Greetings from: A5Y9992TvbUD8Q7bmaCY9j9wztwgcFweUBV5y1JXEyjo
    Program A5Y9992TvbUD8Q7bmaCY9j9wztwgcFweUBV5y1JXEyjo consumed 11880 of 200000 compute units
    Program A5Y9992TvbUD8Q7bmaCY9j9wztwgcFweUBV5y1JXEyjo success

可以看到,initialize 指令成功执行,但程序未被部署或升级,验证了 --skip-deploy 的效果。

总结

  • 无构造函数:Solana 程序的部署无需构造函数,仅通过 anchor deploy 或测试流程完成。
  • 默认可变:程序字节码可升级,最终可选择变为不可变。
  • 无 delegatecall 和不可变变量:Solana 的设计简化了升级逻辑和状态管理。

【笔记配套代码】 https://github.com/0xE1337/rareskills_evm_to_solana 【参考资料】 https://learnblockchain.cn/column/119 https://www.rareskills.io/solana-tutorial

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

0 条评论

请先 登录 后评论
0xE
0xE
0x59f6...a17e
17年进入币圈,Web3 开发者。刨根问底探链上真相,品味坎坷悟 Web3 人生。