Solana 中的所有者与权限

文章详细解释了Solana中'owner'和'authority'的区别,'owner'是程序,'authority'是钱包,程序只能修改其拥有的账户数据,而'authority'通过发送签名交易来请求程序修改数据。文章结构清晰,包含代码示例和图片,适合中级开发者阅读。

展示 Owner vs Authority 的英雄图像

新来者在 Solana 中常常对“owner”和“authority”之间的区别感到困惑。本文力图尽可能简洁地澄清这种混淆。

Owner 和 Authority

只有程序可以向账户写入数据——具体而言,只有向它们拥有的账户写入。程序不能随意向任意账户写入数据。

当然,程序不能自发地向账户写入数据。它们需要从一个钱包接收指令。然而,程序通常只会从特权钱包接受特定账户的写入指令:即 authority

账户的拥有者是一个程序。Authority 是一个钱包。Authority 发送一个交易到程序,该程序可以向账户写入数据。

Solana 中所有账户都有以下字段,这些字段大多不言自明:

  • 公钥
  • lamport 余额
  • owner
  • 可执行(布尔标志)
  • 租金周期(可忽略租金豁免账户)
  • 数据

我们可以通过在终端运行 solana account <我们的钱包地址> 来查看这些(在背景中运行 Solana 验证器):

solana account 命令

注意一些有趣的事情:我们不是我们钱包的拥有者! 地址 111...111system program

为什么系统程序拥有钱包,而不是钱包自己拥有自己?

只有账户的拥有者可以修改其中的数据。

这意味着我们无法直接修改我们的余额。只有系统程序可以做到这一点。要将 SOL 从我们的账户转出,我们发送一个签名交易到系统程序。系统程序验证我们拥有该账户的私钥,然后代表我们修改余额。

这是你在 Solana 中经常会看到的模式:只有账户的拥有者可以修改该账户中的数据。如果程序看到来自一个预定地址的有效签名,它就会修改账户中的数据:即 authority

Authority 是一个地址,程序将在看到有效签名时接受该地址的指令。Authority 不能直接修改账户。它需要通过拥有它正在尝试修改的账户的程序来进行操作。

Authority -> Owner -> Account

然而,拥有者始终是一个程序,而该程序将在交易的签名有效时代表其他人修改账户。

例如,在我们关于 使用不同签名者修改账户 的教程中,我们看到了这一点。

练习:创建一个程序来初始化存储账户。你将需要方便地记录程序和存储账户的地址。考虑将以下代码添加到测试中:

console.log(`program: ${program.programId.toBase58()}`);
console.log(`storage account: ${myStorage.toBase58()}`);

然后在被初始化的账户上运行 solana account <存储账户>。你应该看到拥有者是程序。

这里是运行练习的截图:

通过 : 已初始化

当我们查看存储账户的元数据时,我们看到程序是拥有者。

因为程序拥有存储账户,所以它能够写入数据。用户无法直接写入存储账户,他们需要签署交易并请求程序写入数据。

Solana 中的 owner 和 Solidity 中的 owner 非常不同

在 Solidity 中,我们通常将拥有者称为对智能合约拥有管理权限的特殊地址。“拥有者”并不是以太坊运行级别存在的概念,而是应用于 Solidity 合约的一种设计模式。Solana 中的拥有者则更为根本。在以太坊中,智能合约只能写入自己的存储插槽。想象一下我们有一种机制,可以让以太坊智能合约能够写入其他存储插槽。在 Solana 术语中,它将成为这些存储插槽的 owner

Authority 可以表示谁部署了一个合约以及谁可以发送特定账户的写入交易

Authority 可以是程序级别的一个构造。在我们关于 Anchor 签名者 的教程中,我们制作了一个程序,允许Alice从她的账户中扣除积分并转给其他人。为了知道只有Alice可以发送该账户的扣除交易,我们在账户中存储了她的地址:

##[account]
pub struct Player {
    points: u32,
    authority: Pubkey
}

Solana 使用类似的机制来记住谁部署了一个程序。在我们关于 Anchor 部署 的教程中,我们提到部署程序的钱包也能够升级它。

“升级”一个程序与向其写入新的数据——即新的字节码是一样的。只有程序的拥有者可以向其写入(该程序是 BPFLoaderUpgradeable ,我们将很快看到)。

那么,Solana 怎样知道如何将升级权限赋予部署某个程序的钱包呢?

从命令行查看程序的 authority

在我们部署程序之前,让我们通过在终端运行 solana address 来查看 anchor 正在使用哪个钱包:

solana address

请注意我们的地址是 5jmi...rrTj。现在让我们创建一个程序。

确保 solana-test-validatorsolana logs 在后台运行,然后部署 Solana 程序:

anchor init owner_authority
cd owner_authority
anchor build
anchor test --skip-local-validator

当我们查看日志时,我们看到刚刚部署的程序的地址:

结果:已部署程序

记住,在 Solana 中,一切都是账户,包括程序。现在让我们使用 solana account 6Ye7CgrwJxH3b4EeWKh54NM8e6ZekPcqREgkrn7Yy3Tg 来检查这个账户。我们得到以下结果:

solana account 6Ye7CgrwJxH3b4EeWKh54NM8e6ZekPcqREgkrn7Yy3Tg

注意 authority 字段缺失,因为“authority” 并不是 Solana 账户所拥有的字段。如果你滚动到本文顶部,你会看到控制台中的键与我们在文章顶部列出的字段匹配。

在这里,“owner” 是 BPFLoaderUpgradeable111...111,这是所有 Solana 程序的拥有者。

现在让我们运行 solana program show 6Ye7CgrwJxH3b4EeWKh54NM8e6ZekPcqREgkrn7Yy3Tg,其中 6Ye7...y3TG 是我们的程序地址:

solana program show 6Ye7CgrwJxH3b4EeWKh54NM8e6ZekPcqREgkrn7Yy3Tg

在上述绿色框中,我们看到我们的钱包地址——即用于部署程序的地址,以及我们之前用 solana address 打印的地址:

solana address

但这引出了一个重要问题…

Solana 将程序的“authority”存储在哪里,这个 authority 目前是我们的钱包?

它并不是账户中的一个字段,所以它一定是在某个 Solana 账户的 data 字段中。“authority” 存储在 ProgramData Address 中,该位置存储着程序的字节码:

solana program show

我们钱包(authority)的十六进制编码

在继续之前,将 ProgramData Address 的 base58 编码转换为十六进制表示将是有帮助的。完成此操作的代码在文章末尾提供,但是现在我们请读者接受下面这句话,即我们的 Solana 钱包地址 5jmigjgt77kAfKsHri3MHpMMFPo6UuiAMF19VdDfrrTj 的十六进制表示为:

4663b48dfe92ac464658e512f74a8ee0ffa99fffe89fb90e8d0101a0c3c7767a

查看存储可执行程序的 ProgramData Address 账户中的数据

我们可以使用 solana account 查看 ProgramData 地址账户,但我们也将其发送到临时文件以避免在终端转储太多数据。

solana account FkYygT7X7qjifdxfBVWXTHpj87THJGmtmKUyU4SamfQm > tempfile

head -n 10 tempfile

上面命令的输出显示我们钱包(十六进制)嵌入到 data 中。请注意,黄色下划线的十六进制代码与我们钱包(authority)的十六进制编码匹配:

结果 : ProgramData

程序的字节码存储在单独的账户中,而不是程序的地址

这一点从上面的命令序列中应能隐含得出,但重申是值得的。尽管程序是一个标记为可执行的账户,但字节码并不存储在它自己的数据字段中,而是在另一个账户中(这个账户有点令人困惑地不是可执行的,它仅仅存储字节码)。

练习:你能找到程序将存储字节码的账户地址吗?本文的附录中包含可能有用的代码。

总结

只有程序的拥有者可以更改其数据。Solana 程序的拥有者是 BPFLoaderUpgradeable 系统程序,因此按照默认设置,部署程序的钱包无法更改存储在账户中的数据(字节码)。

为了启用程序的升级,Solana 运行时将部署者的钱包嵌入到程序的字节码中。它将这个字段称为“authority”。

当部署钱包尝试升级字节码时,Solana 运行时将检查事务签名者是否为 authority。如果事务签名者与 authority 匹配,则 BPFLoaderUpgradeable 将代表 authority 更新程序的字节码。

附录:将 base58 转换为十六进制

以下 Python 代码将完成转换。此代码由一个聊天机器人生成,因此仅供参考:

def decode_base58(bc, length):
    base58_digits = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
    n = 0
    for char in bc:
        n = n * 58 + base58_digits.index(char)
    return n.to_bytes(length, 'big')

def find_correct_length_for_decoding(base58_string):
    for length in range(25, 50):  # 尝试从 25 到 50 的长度
        try:
            decoded_bytes = decode_base58(base58_string, length)
            return decoded_bytes.hex()
        except OverflowError:
            continue
    return None

## 要转换的 Base58 字符串
base58_string = "5jmigjgt77kAfKsHri3MHpMMFPo6UuiAMF19VdDfrrTj"

## 转换并获取十六进制字符串
hex_string = find_correct_length_for_decoding(base58_string)
print(hex_string)

了解更多

请查阅我们的 Solana 开发课程 以了解更多 Solana 主题!如需其他区块链主题,请查看我们的 区块链训练营

原发布于 2024 年 3 月 11 日

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

0 条评论

请先 登录 后评论
RareSkills
RareSkills
https://www.rareskills.io/