Solana内部机制第二部分:Solana程序是如何部署和升级的

  • Sec3dev
  • 发布于 2022-01-17 14:52
  • 阅读 45

本文详细介绍了Solana程序的部署与升级过程,包括程序账户的定义与属性、部署所需的每一步,以及如何进行程序升级和关闭操作。同时强调了升级权限的重要性与安全性问题。通过示例和代码块,提供了清晰的技术细节和步骤说明。

当你将智能合约部署到 Solana 主网 时,Solana 内部发生了什么?Solana 程序可以被修改或关闭吗?如何升级一个 Solana 程序?谁有权修改 Solana 程序?

本文重点关注 Solana 程序的可升级性,并突显一些细节。

以下是一些要点总结:

  • Solana 程序可以被修改和升级(默认情况下)
  • BPFLoaderUpgradeab1e 加载器是每个可升级 Solana 程序账户的所有者
  • Solana 程序数据(即智能合约代码)存储在一个单独的缓冲账户中,并且具有最大大小限制。
  • 升级权限拥有超级权限,必须得到安全管理
  • 可升级 Solana 程序的用户应当谨慎,以避免 Rug pull
  • 对 Solana 程序的更新可能引入新的安全漏洞,必须经过审核

Solana 程序账户

每个用户部署的智能合约都有一个 Solana 程序账户,该账户具有多个重要属性:program_idownerprogram_dataauthority 等等。

图1. jet-v1 的程序账户信息 (链接)

注意,这些信息属性并不存储在单个可执行程序中。程序数据和权限实际上存储在一个从 program_id 派生的单独账户(programdata)中。有关更多细节,请查看 这篇文章(来源:starry.soltmpjail

program_id 是 Solana 程序的地址。我们以 jet-v1 (program_id JPv1rCqrhagNNmJVM5J1he7msQ5ybtvE1nNuHpDHMNU)举例。图1显示了来自 explorer.solana.com 的屏幕截图。

需要注意几个事项:

  • Solana 程序是可升级的
  • 所有者是 BPFLoaderUpgradeab1eBPFLoaderUpgradeab1e11111111111111111111111
  • 具有 升级权限 CkkWJtdPoq22CVdfWBhV5vo9MXNVaPXJAjrVmsRpYGC1
  • executable_data 账户 地址是 45X4uzRnRvZoiG6X5ho6V8FJUU7HVxDApuyoL8mwgiP9

executable_data 账户 包含 jet-v1 的实际 BPF 字节码,其数据长度为 1827341 字节(>1.8MB),如下面的图2所示。

图2. jet-v1 的 executable_data 账户信息(链接

要在终端中显示 jet-v1 的 Solana 程序账户的详细信息,请运行:

要在终端中显示 jet-v1 的 Solana executable_data 账户的详细信息,请运行:

关于部署 Solana 程序

根据 Solana 文档,要部署 Solana 程序,例如 jet-v1,只需运行以下命令,该命令将在 Solana 集群上传已编译的 BPF 字节码(即 ELF 共享对象 jet.so):

然而,在 solana program deploy 后,部署一个 Solana 程序是相当复杂的,可能需要许多交易:

  1. 初始化一个程序账户(第一次交易
  2. 将 BPF 字节码上传到程序账户的数据缓冲区(一次或多次交易
  3. 通过标记程序账户为可执行来完成部署(最后交易

步骤 1:初始化程序账户

步骤 1 通过提交一个包含 system_instruction::create_account 指令的交易来完成:

  • config.signers[0].pubkey()program_id 替代要创建的智能合约。可以通过 --program-id <PROGRAM_ID> 指定,否则从默认位置加载的密钥对中获取。

  • buffer_pubkey 是数据缓冲区的地址,即 executabledata 账户。可以通过 **--buffer <BUFFER_SIGNER >_ 指定,或者由 create_ephemeral_keypair()** 自动生成:

  • minimum_balance 是为了租户豁免而转移到程序账户的最小 lamports 数量。它由 minimum_balance = rpc_client.get_minimum_balance_for_rent_exemption(program_data.len()) 计算得出。

  • buffer_data_len 是数据长度,即 BPF 字节码的字节数。Solana BPF 程序中的最大指令数存在限制:

  • loader_id 指定程序账户的所有者。可以是 BPFLoader2(最新的 Solana BPF 加载器)、BPFLoader(原始且现已弃用的 Solana BPF 加载器)。

程序账户的所有者也可以是 BPFLoaderUpgradeab1e。实际上,默认情况下所有用户部署的 Solana 程序都是用 BPFLoaderUpgradeab1e 部署的,因此是可升级的 .

注意: 在此上下文中 loader_id 不能是 BPFLoaderUpgradeab1eBPFLoaderUpgradeab1e 的部署步骤与 BPFLoader2 和 BPFLoader 不同,因为所有步骤都发生在 单个 交易中 . 有关更详细的信息见“部署可升级的 Solana 程序”一节。(来源BlockBandit 建议在此讨论 BPFLoaderUpgradeab1e 以避免混淆)

步骤 2:上传 BPF 字节码

步骤 2 首先通过验证 BPF 字节码(链下)完成,然后提交一次或多次交易,通过 LoaderInstruction::Write 指令,将字节码上传到数据缓冲账户:

注意,Solana 上的单个交易有最大大小限制:solana_sdk::packet::PACKET_DATA_SIZE(小于 1280 字节,由 IPv6 数据包限制决定)。

PACKET_DATA_SIZE 限制来自 Solana packet.rs

对于数据长度大于 PACKET_DATA_SIZE 的 BPF 字节码,必须将其拆分为多个小块,并为每个块提交一笔交易。

参数 offset 和字节到 loader_instruction::write 指定一个块的偏移量和最大块大小。

对于典型的 Solana 程序,此步骤可能需要几百次或几千次交易。例如,部署 jet-v1 大约需要 ~1500 笔交易(在 Solana 上平均不到一秒)。

步骤 3:完成部署

此步骤通过 LoaderInstruction::Finalize 指令提交一笔交易:

该指令将调用 Solana 运行时中的 bpf_loader(带有 loader_id),将程序的可执行标志设置为 true

部署可升级的 Solana 程序

默认情况下,所有用户部署的 Solana 程序都是通过 BPFLoaderUpgrad eab1e(即 bpf_loader_upgradeable::id())加载器进行部署的。

该部署通过 单个交易 提交 UpgradeableLoaderInstruction::DeployWithMaxDataLen 指令:

该指令将在 Solana 运行时中调用 BPFLoaderUpgradeab1e 加载器,创建一个 ProgramData 账户以存储缓冲数据,并最终将程序设置为可执行。

为了为未来的升级分配空间,ProgramData 账户的 max_data_len 设置为 BPF 字节码大小的两倍。

关于升级 Solana 程序

Solana 程序默认可以升级。即,可以将新的共享对象(BPF 字节码)重新部署到相同的 Solana 程序账户。

这可以由程序的升级权限进行,该权限可以在原始部署期间通过 --upgrade-authority <UPGRADE_AUTHORITY_SIGNER> 指定,否则设置为默认配置的密钥对。

程序的升级权限也可以通过 UpgradeableLoaderInstruction::SetAuthority 指令(在由当前升级权限签署的交易中)更改为 new_authority

当 Solana 程序通过升级权限重新部署时,它首先为新的 BPF 字节码创建一个新的数据缓冲账户,然后调用 UpgradeableLoaderInstruction::Upgrade 指令,更新 ProgramData 账户以存储新的缓冲数据。

将 Solana 程序设置为永久不可变

Solana 还提供选项 --final 使用 BPFLoader2 在部署时 (当提供了 --final 时,程序将不可升级)。**

如果需要对已完成的程序进行任何更改(功能、补丁等),必须将新程序部署到新的程序 ID。

关于关闭 Solana 程序

Solana 程序和缓冲账户都可以由其升级权限关闭,并将其 lamport 余额转移到接收者的账户。

要关闭一个程序账户:

内部,它调用 UpgradeableLoaderInstruction::Close 指令,该指令更新账户 lamports 并将 close_account 的状态设置为 UpgradeableLoaderState::Uninitialized

最后提示:谨慎升级 Solana 程序

与以太坊相比,智能合约的可升级性是 Solana 的一大特色。这一设计使得 Solana 应用程序更容易集成新功能。然而,也有一些注意事项:

1. 升级权限拥有超级权限

升级权限必须得到安全管理。如果升级权限变得恶意或私钥被攻击者获得,则 Solana 程序可以被直接关闭或随时更改,以锁定或窃取用户的资金。

2. 可升级 Solana 程序的用户应当得到通知

如果你正在使用一个可升级的程序,找到一种方法在程序升级时得到通知,以避免恶意行为如 Rug pull。

3. 对 Solana 程序的更新必须谨慎

即使是微小的程序更改也可能引入新的安全漏洞,必须经过仔细测试和审核。

作为一个例子,最近由于一次临时升级以包含新功能,jet-v1 中发现了一个关键漏洞。幸运的是,这个漏洞首先由一个白帽子发现和报告。关于详细情况,请见 这条推文


关于 sec3(前称 Soteria)

sec3 是一家安全研究公司,旨在为数百万用户准备 Solana 项目。sec3 的 Launch Audit 是一项严格的、由研究人员主导的代码检查,调查并证明主网级智能合约的质量;sec3 的持续审计软件平台 X-ray 与 GitHub 集成,逐步扫描拉取请求,帮助项目在部署之前巩固代码;sec3 的部署后安全解决方案 WatchTower 确保资金的安全。sec3 正在为 Web3 项目构建基于技术的可扩展解决方案,以确保协议在扩展时保持安全。

要了解更多关于 sec3 的信息,请访问 https://www.sec3.dev

  • 原文链接: sec3.dev/blog/solana-int...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
Sec3dev
Sec3dev
https://www.sec3.dev/